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
| 項番 | カラム名 | 型 | 属性 | 概要 |
| --: | --- | --- | --- | --- |
-| 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) | | 著者名 |
| 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 | 更新日時 |
+
+注: 画像をロードした場合の管理用
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
session[:userId] = id;
redirect "/user_home"
rescue UserAccount::AlreadyInstanceError
- raise WebError.new(406),
- "すでに登録済みのアカウント名が指定されています。"
+ raise WebError.new(status: 406, message: "すでに登録済みのアカウント名が指定されています。")
end
end
redirect "/user_home"
rescue UserAccount::NotFoundInstanceError,
UserAccount::AuthenticationError
- raise WebError.new(401),
- "認証に失敗しました アカウント、 パスワードを確認してください。"
+ raise WebError.new(status: 401, message: "認証に失敗しました アカウント、 パスワードを確認してください。")
end
end
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
# 最終ログイン情報登録
# エラーページ
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
# ユーザ情報
class User < ActiveRecord::Base
+ # ユーザロール
+ #管理者権限
+ ROLE_ADMIN = 0
+ #一般権限
+ ROLE_NORMAL = 8
+ #パスワード忘れ中
+ ROLE_FORGOT = 10
+
# 正規表現によるレコード探索
# @param [Symbol] key カラム名
# @param [String] pattern 正規表現パターン
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
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 ユーザ名
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
end
return user
end
+
+ # ユーザ一覧の取得
+ # @param [Integer] id 取得対象ユーザID
+ # @return [Array<User>] 全ユーザ情報の一覧
+ # @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
- # encoding: utf-8
- error_message = @error_message
-
+- refs = @refs
.error
%h3
エラーが発生しました。
.buttoms
.buttoms__push
- %a{ :href => '/'}
- メインにもどる
+ - if refs == nil
+ %a{ :href => '/'}
+ メインにもどる
+ - else
+ %a{ :href => refs}
+ もどる
- title_name = @username+"書籍"
- id = @id
- user_name = @username
+ - is_admin = @is_admin
- else
- title_name = "書籍一覧管理"
!!!
%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
%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" }
ログアウト
%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 => 'もどる' }
- # encoding: utf-8
%h1
- 書籍管理サーバ
+ 蔵書管理サーバ
.buttoms
.buttoms__push
}
}
-.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
}
%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 => 'もどる' }
--- /dev/null
+- # 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 => 'もどる' }
+
+
%h2
ここは #{user_name} さんのホームページです
-%p
+.message
あなたの最近登録した本は以下になります。
%ul
--- /dev/null
+// メールのフォームチェック用
+
+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(''); // エラーメッセージのクリア
+ }
+}