From: OHASHI, Norikazu Date: Sun, 21 Apr 2019 14:06:55 +0000 (+0900) Subject: 以下の追加と修正を実施 X-Git-Url: http://www.wald-der-katze.sakura.ne.jp/git/gitweb.cgi?a=commitdiff_plain;h=2bfa354a55c2dd20ada2dafd227d217dd9e27e7e;p=book_server.git 以下の追加と修正を実施 * ユーザ情報編集機能などを追加 * パスワードのフォームチェックをjava-script * フォームのデザインを修正 --- diff --git a/readme.md b/readme.md index 1df7530..6b16fb5 100644 --- a/readme.md +++ b/readme.md @@ -28,7 +28,7 @@ login.haml # user login view logout.haml # user logout view user_home.haml # user default home view - account.haml # setup account view + user_edit.haml # change user info view list.haml # list of books view search.haml # search books view detail.haml # detail of book parameter view @@ -56,7 +56,7 @@ | 項番 | カラム名 | 型 | 属性 | 概要 | | --: | --- | --- | --- | --- | -| 1 | isbn | VARCHAR(14) | NOT NULL | ISBNコード | +| 1 | isbn | VARCHAR(14) | NOT NULL, PRIMARY KEY | ISBNコード | | 2 | title | VARCHAR(255) | NOT NULL | 書名 | | 3 | volume | INTEGER | | 巻数 | | 4 | author | VARCHAR(127) | | 著者名 | @@ -77,3 +77,16 @@ | 5 | creat_at | DATETIME | NOT NULL | 登録日時 | | 6 | update_at | DATETIME | NOT NULL | 更新日時 | 注: isdn + user_id で複合キーとする。 + + +### 書影管理テーブル (book\_shadows) +| 項番 | カラム名 | 型 | 属性 | 概要 | +| --: | --- | --- | --- | --- | +| 1 | key_hash | VARCHAR(60) | NOT NULL, PRIMARY KEY | SHA125 HASH (アクセスキー) | +| 2 | isbn | VARCHAR(14) | NOT NULL, UNIQUE | 対象ISBN | +| 3 | mime_type | VARCHAR(255) | NOT NULL | 画像のMIME TYPE | +| 4 | shadow | LARGETEXT | NOT NULL | 画像のデータ(BASE64) | +| 5 | creat_at | DATETIME | NOT NULL | 登録日時 | +| 6 | update_at | DATETIME | NOT NULL | 更新日時 | + +注: 画像をロードした場合の管理用 diff --git a/sinatra/app/controllers/web_gui.rb b/sinatra/app/controllers/web_gui.rb index 5238d77..7093cea 100644 --- a/sinatra/app/controllers/web_gui.rb +++ b/sinatra/app/controllers/web_gui.rb @@ -13,27 +13,28 @@ require_relative '../models/users_db' class WebGui < Sinatra::Base # エラーステータス設定 - # @attr_reader [Integer] status HTTTP レスポンスステータス + # @attr_reader [Hash] params エラー処理用パラメータ class WebError < StandardError - attr_reader :status + attr_reader :params - # @param [Integer] status HTTP レスポンスステータス - def initialize(status) - @status = status + # @param [Hash] params エラー処理用パラメータ + def initialize(params) + @params = params end end set :root, File.join(File.dirname(__FILE__), '..') set :views, Proc.new {File.join(root, "views")} + set :public, Proc.new {File.join(root, "../public")} set :haml, :format => :html5 set :environment, :production use Rack::Session::Cookie, - :expire_after => 300, + :expire_after => 1200, :secret => 'change' # スタイルシート - get '/style.css' do + get '/css/style.css' do scss :'scss/style' end @@ -65,8 +66,7 @@ class WebGui < Sinatra::Base session[:userId] = id; redirect "/user_home" rescue UserAccount::AlreadyInstanceError - raise WebError.new(406), - "すでに登録済みのアカウント名が指定されています。" + raise WebError.new(status: 406, message: "すでに登録済みのアカウント名が指定されています。") end end @@ -90,8 +90,7 @@ class WebGui < Sinatra::Base redirect "/user_home" rescue UserAccount::NotFoundInstanceError, UserAccount::AuthenticationError - raise WebError.new(401), - "認証に失敗しました アカウント、 パスワードを確認してください。" + raise WebError.new(status: 401, message: "認証に失敗しました アカウント、 パスワードを確認してください。") end end @@ -100,16 +99,70 @@ class WebGui < Sinatra::Base get '/user_home' do id = session[:userId] if (id == nil) - raize WebError.new(408), - "セッション期限切れです。再ログインをしてください。" + raize WebError.new(status: 408, message: "セッション期限切れです。再ログインをしてください。") end user = UserAccount.getUser(id) @id = id @username = user.full_name + @is_addmin = user.isAddmin @newest_list = [ "書籍1", "書籍2", "書籍3"] haml :user_home end + # ユーザ情報編集ページ + # @raise [WebError] セッションの期限切れ + # @raise [WebError] ユーザID不正 + get '/user_edit' do + id = session[:userId] + if (id == nil) + raize WebError.new(status: 408, message: "セッション期限切れです。再ログインをしてください。") + end + begin + user = UserAccount.getUser(id) + @id = id + @username = user.full_name + @account = user.user_name + @email = user.email + rescue UserAccount::NotFoundInstanceError + raize WebError.new(status: 400, message: "該当するユーザが存在しません。") + end + haml :user_edit + end + + # ユーザ情報編集ページ(POST) + # @post_param name [String] ログインユーザ名, + # @post_param try_pass [String] 旧パスワード + # @post_param new_pass [String] 新パスワード + # @post_param full_name [String] フルネーム + # @post_param email [String] Eメール + # @raise [WebError] ユーザ情報編集失敗 + post '/user_edit' do + id = session[:userId] + name = params[:name] + full_name = params[:full_name] + email = params[:email] + try_pass = params[:try_pass] + new_pass = params[:new_pass] + + if (id == nil) + raise WebError.new(staut: 408, message: "セッション期限切れです。再ログインをしてください。") + end + begin + if (new_pass != "") + check_id = UserAccount.checkPasswd(name, try_pass) + if (check_id != id) + raise StandardError, "アカウント名とIDが不正" + end + end + UserAccount.changeUser(id, new_pass, full_name, email) + redirect "/user_home" + rescue StandardError, + UserAccount::NotFoundInstanceError, + UserAccount::AuthenticationError + raise WebError.new(statu: 400, message: "ユーザ情報の編集に失敗しました。", refs: "/user_edit") + end + end + # ログアウトページ get '/logout' do # 最終ログイン情報登録 @@ -119,8 +172,9 @@ class WebGui < Sinatra::Base # エラーページ error WebError do e = env['sinatra.error'] - status e.status - @error_message = e.message + status e.params[:status] + @refs = e.params[:refs] + @error_message = e.params[:message] haml :error end end diff --git a/sinatra/app/models/users_db.rb b/sinatra/app/models/users_db.rb index d4ade87..5d17800 100644 --- a/sinatra/app/models/users_db.rb +++ b/sinatra/app/models/users_db.rb @@ -13,6 +13,14 @@ ActiveRecord::Base.establish_connection(:development) # ユーザ情報 class User < ActiveRecord::Base + # ユーザロール + #管理者権限 + ROLE_ADMIN = 0 + #一般権限 + ROLE_NORMAL = 8 + #パスワード忘れ中 + ROLE_FORGOT = 10 + # 正規表現によるレコード探索 # @param [Symbol] key カラム名 # @param [String] pattern 正規表現パターン @@ -21,15 +29,18 @@ class User < ActiveRecord::Base column = columns_hash[key.to_s].name where("`#{table_name}`.`#{column}` REGEXP ?", pattern) end + + # 管理者権限か否か + # @return [Boolean] true: 管理者 + # @return [Boolean] false: 管理者ではない + def isAddmin + return user_role == ROLE_ADMIN + end end # ユーザ管理 class UserAccount - # ユーザロール - ROLE_ADMIN = 0 #管理者権限 - ROLE_NORMAL = 8 #一般権限 - ROLE_FORGOT = 10 #パスワード忘れ中 # ユーザ認証エラー class AuthenticationError < SecurityError @@ -47,6 +58,19 @@ class UserAccount class DbAccessError < StandardError end + # ユーザが管理者であるかをチェック + # @param [Integer] id チェック対象ユーザID + # @return [Boolean] true: 管理者 + # @return [Boolean] false: 管理者ではない + def self.checkAdmin(id) + user = User.find_by(user_id: id) + if (user == nil) + return false + end + return user.isAddmin() + end + + private_class_method :checkAdmin # ユーザアカウントを作成 # @param [String] name ユーザ名 @@ -74,7 +98,7 @@ class UserAccount user.email = email user.passwd_salt = passwd_salt user.passwd_hash = passwd_hash - user.user_role = ROLE_NORMAL + user.user_role = User::ROLE_NORMAL user.create_at = DateTime.now user.update_at = DateTime.now user.save @@ -119,4 +143,53 @@ class UserAccount end return user end + + # ユーザ一覧の取得 + # @param [Integer] id 取得対象ユーザID + # @return [Array] 全ユーザ情報の一覧 + # @raise [AuthenticationError] ユーザ権限不正 + def self.getUserList(id) + if (checkAdmin(id)) + raise AuthenticationError + end + return User.all + end + + # ユーザ情報の変更 + # @param [Integer] id 変更対象のユーザID + # @param [String] passwd 変更するパスワード (未修正の場合は空文字列) + # @param [String] full_name 変更するフルネーム (未修正の場合は空文字列) + # @param [String] email 変更するEメールアドレス (未修正の場合は空文字列) + def self.changeUser(id, passwd, full_name, email) + user = User.find_by(user_id: id) + change_f = false + if (user == nil) + raise NotFoundInstanceError + end + + # パスワード更新 + if (passwd != "") + user.passwd_hash = BCrypt::Engine.hash_secret(passwd, user.passwd_salt) + change_f = true + end + + # フルネーム更新 + if ((full_name != "") && (full_name != user.full_name) ) + user.full_name = full_name + change_f = true + end + + # Eメール更新 + if ((email != "") && (email != user.email)) + user.email = email + change_f = true + end + + # 更新内容の適用 + if (change_f) + user.update_at = DateTime.now + user.save + end + end + end diff --git a/sinatra/app/views/error.haml b/sinatra/app/views/error.haml index 06a5929..907acc0 100644 --- a/sinatra/app/views/error.haml +++ b/sinatra/app/views/error.haml @@ -1,6 +1,6 @@ - # encoding: utf-8 - error_message = @error_message - +- refs = @refs .error %h3 エラーが発生しました。 @@ -8,5 +8,9 @@ .buttoms .buttoms__push - %a{ :href => '/'} - メインにもどる + - if refs == nil + %a{ :href => '/'} + メインにもどる + - else + %a{ :href => refs} + もどる diff --git a/sinatra/app/views/layout.haml b/sinatra/app/views/layout.haml index 077b8a7..c92384d 100644 --- a/sinatra/app/views/layout.haml +++ b/sinatra/app/views/layout.haml @@ -3,6 +3,7 @@ - title_name = @username+"書籍" - id = @id - user_name = @username + - is_admin = @is_admin - else - title_name = "書籍一覧管理" !!! @@ -11,7 +12,8 @@ %meta{ :charset => 'utf-8'} %title #{title_name} - %link{ :rel => 'stylesheet', :href => '/style.css'} + %link{ :rel => 'stylesheet', :href => '/css/style.css'} + %script{ :src => '/scripts/default.js'} %body - if user_name == nil @@ -27,8 +29,12 @@ %a{ :href => "/book_list" } 書籍一覧 %br - %a{ :href => "/user_info" } - ユーザ情報 + - if is_admin + %a{ :href => "/user_list" } + ユーザ情報変更 + - else + %a{ :href => "/user_edit" } + ユーザ情報変更 %br %a{ :href => "/logout" } ログアウト diff --git a/sinatra/app/views/login.haml b/sinatra/app/views/login.haml index 7a0612e..2a4c72f 100644 --- a/sinatra/app/views/login.haml +++ b/sinatra/app/views/login.haml @@ -6,16 +6,21 @@ %hr %form{ :action => "/login", :method => "post"} - アカウント: - %input{ :name => 'name', :size => 10, :maxlength => 10} - %br - - パスワード: - %input{ :name => 'passwd', :type => 'password', :pattern => '.{6,}' } - %br - + .formstyle + .params + .item + %label{ :for => 'name' } + %span + アカウント: + %input{ :name => 'name', :size => 10, :maxlength => 10, :id => 'name', :required => true} + .item + %label{ :for => 'passwd' } + %span + パスワード: + %input{ :name => 'passwd', :type => 'password', :id => 'passwd', :pattern => '.{6,}', :required => true} %hr - - %input{ :type => 'submit', :value => '送信'} - %input{ :type => 'reset', :value => 'リセット'} + + .buttons + %input{ :type => 'submit', :value => '送信'} + %input{ :type => 'button', :onclick =>"location.href='/'", :value => 'もどる' } diff --git a/sinatra/app/views/main.haml b/sinatra/app/views/main.haml index 1719528..1089886 100644 --- a/sinatra/app/views/main.haml +++ b/sinatra/app/views/main.haml @@ -1,7 +1,7 @@ - # encoding: utf-8 %h1 - 書籍管理サーバ + 蔵書管理サーバ .buttoms .buttoms__push diff --git a/sinatra/app/views/scss/style.scss b/sinatra/app/views/scss/style.scss index 89c02ee..aaa3eca 100644 --- a/sinatra/app/views/scss/style.scss +++ b/sinatra/app/views/scss/style.scss @@ -63,10 +63,33 @@ ul { } } -.forms { +.message { + margin-left: 10px; + margin-right: 10px; text-align: left; } +.formstyle { + margin: 0, auto; + .params { + margin-left: 20px; + text-align: left; + display: block; + .item { + label { + margin-right: 10px; + span { + width:220px; + display: inline-block; + } + } + } + } + .buttoms { + display: block; + } +} + .error { background: #cd5e3c } diff --git a/sinatra/app/views/signup.haml b/sinatra/app/views/signup.haml index 528d1a4..e7ceb8c 100644 --- a/sinatra/app/views/signup.haml +++ b/sinatra/app/views/signup.haml @@ -9,27 +9,41 @@ %hr %form{ :action => "/signup", :method => "post"} - .forms - %p - アカウント: - %input{ :name => 'name', :size => 10, :maxlength => 10} + .formstyle + .params + .item + %label{ :for => 'name' } + %span + アカウント: + %input{ :name => 'name', :id => 'name', :size => 10, :maxlength => 10, :required => true} + + .item + %label{ :for => 'full_name' } + %span + フルネーム: + %input{ :name => 'full_name', :id => 'full_name', :size => 30, :maxlength => 127} + + .item + %label{ :for => 'passwd' } + %span + パスワード: + %input{ :name => 'passwd', :type => 'password', :id => 'passwd', :pattern => '.{6,}', :required => true } - %p - フルネーム: - %input{ :name => 'full_name', :size => 30, :maxlength => 127} + .item + %label{ :for => 'passwdConfirm'} + %span + パスワード(確認用): + %input{ :type => 'password', :id => 'passwdConfirm', :pattern => '.{6,}', :required => true, :oninput => 'checkPasswd(this)' } - %p - パスワード: - %input{ :name => 'passwd', :type => 'password', :pattern => '.{6,}' } - + .item + %label{ :for => 'email' } + %span + Eメールアドレス: + %input{ :name => 'email', :type => 'email', :id => 'email', :size => 30, :maxlength => 127, :required => true} - %p - Eメールアドレス: - %input{ :name => 'email', :type => 'email', :size => 30, :maxlength => 127} - - %hr - - %input{ :type => 'submit', :value => '送信'} - %input{ :type => 'reset', :value => 'リセット'} + %hr + .buttons + %input{ :type => 'submit', :value => '送信'} + %input{ :type => 'button', :onclick =>"location.href='/'", :value => 'もどる' } diff --git a/sinatra/app/views/user_edit.haml b/sinatra/app/views/user_edit.haml new file mode 100644 index 0000000..21ce8cc --- /dev/null +++ b/sinatra/app/views/user_edit.haml @@ -0,0 +1,60 @@ +- # encoding: utf-8 +- id = @id +- account = @account +- username = @username +- email = @email + +%h3 + #{username} のユーザデータを変更できます。 + +.message + パスワードを変更する際には、現在のパスワードと + 新しいパスワードを入力してください。 + +%hr + +%form{ :action => "/user_edit", :method => "post"} + .formstyle + .params + .item + %label{ :for => 'name' } + %span + アカウント: + %input{ :name => 'name', :id => 'name', :value => account, :readonly => true} + + .item + %label{ :for => 'full_name' } + %span + フルネーム: + %input{ :name => 'full_name', :id => 'full_name', :size => 30, :value => username, :maxlength => 127} + + .item + %label{ :for => 'old_passwd' } + %span + 現在のパスワード: + %input{ :name => 'try_pass', :type => 'password', :id => 'old_passwd'} + + .item + %label{ :for => 'passwd' } + %span + 新しいパスワード: + %input{ :name => 'new_pass', :type => 'password', :id => 'passwd', :pattern => '.{6,}', :oninput => 'checkOldPass(this)' } + + .item + %label{ :for => 'passwdConfirm'} + %span + 新しいパスワード(確認用): + %input{ :type => 'password', :id => 'passwdConfirm', :pattern => '.{6,}', :oninput => 'checkPasswd(this)' } + + .item + %label{ :for => 'email' } + %span + Eメールアドレス: + %input{ :name => 'email', :type => 'email', :id => 'email', :size => 30, :maxlength => 127, :value => email } + + %hr + .buttons + %input{ :type => 'submit', :value => '送信'} + %input{ :type => 'button', :onclick =>"location.href='/user_home'", :value => 'もどる' } + + diff --git a/sinatra/app/views/user_home.haml b/sinatra/app/views/user_home.haml index 9bb1415..fbed01a 100644 --- a/sinatra/app/views/user_home.haml +++ b/sinatra/app/views/user_home.haml @@ -5,7 +5,7 @@ %h2 ここは #{user_name} さんのホームページです -%p +.message あなたの最近登録した本は以下になります。 %ul diff --git a/sinatra/public/scripts/default.js b/sinatra/public/scripts/default.js new file mode 100644 index 0000000..0d7fe2f --- /dev/null +++ b/sinatra/public/scripts/default.js @@ -0,0 +1,39 @@ +// メールのフォームチェック用 + +function checkEmail(input){ + var mail = document.getElementById("email").value; //メールの値を取得 + var mailConfirm = input.value; //メール確認用の値を取得(引数input) + + // パスワードの一致確認 + if(mail != mailConfirm){ + input.setCustomValidity('メールアドレスが一致しません'); // エラーメッセージのセット + }else{ + input.setCustomValidity(''); // エラーメッセージのクリア + } +} + +// パスワードのフォームチェック用 (新旧の確認) +function checkOldPass(input){ + var old_passwd = document.getElementById("old_passwd").value; //旧パスワードの値を取得 + var new_passwd = input.value; //新パスワードの値を取得 + + // パスワードの一致確認 + if((old_passwd != "") && (old_passwd == new_passwd)){ + input.setCustomValidity('現在のパスワードと新しいパスワードが同じです。'); // エラーメッセージのセット + }else{ + input.setCustomValidity(''); // エラーメッセージのクリア + } +} + +// パスワードのフォームチェック用 +function checkPasswd(input){ + var passwd = document.getElementById("passwd").value; //パスワードの値を取得 + var passwdConfirm = input.value; //パスワード(確認用)の値を取得 + + // パスワードの一致確認 + if(passwd != passwdConfirm){ + input.setCustomValidity('パスワードが一致しません。'); // エラーメッセージのセット + }else{ + input.setCustomValidity(''); // エラーメッセージのクリア + } +}