boxroom 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +50 -0
  4. data/Rakefile +36 -0
  5. data/app/assets/config/boxroom_manifest.js +2 -0
  6. data/app/assets/images/boxroom/clipboard.png +0 -0
  7. data/app/assets/images/boxroom/clipboard_add.png +0 -0
  8. data/app/assets/images/boxroom/copy.png +0 -0
  9. data/app/assets/images/boxroom/delete.png +0 -0
  10. data/app/assets/images/boxroom/edit.png +0 -0
  11. data/app/assets/images/boxroom/exclamation.png +0 -0
  12. data/app/assets/images/boxroom/extend.png +0 -0
  13. data/app/assets/images/boxroom/failed.png +0 -0
  14. data/app/assets/images/boxroom/file.png +0 -0
  15. data/app/assets/images/boxroom/file_add.png +0 -0
  16. data/app/assets/images/boxroom/fileicons/7z.png +0 -0
  17. data/app/assets/images/boxroom/fileicons/ai.png +0 -0
  18. data/app/assets/images/boxroom/fileicons/aif.png +0 -0
  19. data/app/assets/images/boxroom/fileicons/aiff.png +0 -0
  20. data/app/assets/images/boxroom/fileicons/audio.png +0 -0
  21. data/app/assets/images/boxroom/fileicons/bz2.png +0 -0
  22. data/app/assets/images/boxroom/fileicons/c.png +0 -0
  23. data/app/assets/images/boxroom/fileicons/conf.png +0 -0
  24. data/app/assets/images/boxroom/fileicons/cpp.png +0 -0
  25. data/app/assets/images/boxroom/fileicons/cs.png +0 -0
  26. data/app/assets/images/boxroom/fileicons/css.png +0 -0
  27. data/app/assets/images/boxroom/fileicons/csv.png +0 -0
  28. data/app/assets/images/boxroom/fileicons/divx.png +0 -0
  29. data/app/assets/images/boxroom/fileicons/doc.png +0 -0
  30. data/app/assets/images/boxroom/fileicons/docx.png +0 -0
  31. data/app/assets/images/boxroom/fileicons/dot.png +0 -0
  32. data/app/assets/images/boxroom/fileicons/fla.png +0 -0
  33. data/app/assets/images/boxroom/fileicons/gif.png +0 -0
  34. data/app/assets/images/boxroom/fileicons/gz.png +0 -0
  35. data/app/assets/images/boxroom/fileicons/htm.png +0 -0
  36. data/app/assets/images/boxroom/fileicons/html.png +0 -0
  37. data/app/assets/images/boxroom/fileicons/image.png +0 -0
  38. data/app/assets/images/boxroom/fileicons/java.png +0 -0
  39. data/app/assets/images/boxroom/fileicons/jpeg.png +0 -0
  40. data/app/assets/images/boxroom/fileicons/jpg.png +0 -0
  41. data/app/assets/images/boxroom/fileicons/js.png +0 -0
  42. data/app/assets/images/boxroom/fileicons/mdb.png +0 -0
  43. data/app/assets/images/boxroom/fileicons/mdbx.png +0 -0
  44. data/app/assets/images/boxroom/fileicons/mov.png +0 -0
  45. data/app/assets/images/boxroom/fileicons/mp3.png +0 -0
  46. data/app/assets/images/boxroom/fileicons/mpg.png +0 -0
  47. data/app/assets/images/boxroom/fileicons/ogg.png +0 -0
  48. data/app/assets/images/boxroom/fileicons/pdf.png +0 -0
  49. data/app/assets/images/boxroom/fileicons/php.png +0 -0
  50. data/app/assets/images/boxroom/fileicons/pl.png +0 -0
  51. data/app/assets/images/boxroom/fileicons/png.png +0 -0
  52. data/app/assets/images/boxroom/fileicons/ppt.png +0 -0
  53. data/app/assets/images/boxroom/fileicons/pptx.png +0 -0
  54. data/app/assets/images/boxroom/fileicons/ps.png +0 -0
  55. data/app/assets/images/boxroom/fileicons/py.png +0 -0
  56. data/app/assets/images/boxroom/fileicons/ram.png +0 -0
  57. data/app/assets/images/boxroom/fileicons/rar.png +0 -0
  58. data/app/assets/images/boxroom/fileicons/rb.png +0 -0
  59. data/app/assets/images/boxroom/fileicons/rm.png +0 -0
  60. data/app/assets/images/boxroom/fileicons/rtf.png +0 -0
  61. data/app/assets/images/boxroom/fileicons/sql.png +0 -0
  62. data/app/assets/images/boxroom/fileicons/swf.png +0 -0
  63. data/app/assets/images/boxroom/fileicons/tar.png +0 -0
  64. data/app/assets/images/boxroom/fileicons/tgz.png +0 -0
  65. data/app/assets/images/boxroom/fileicons/txt.png +0 -0
  66. data/app/assets/images/boxroom/fileicons/video.png +0 -0
  67. data/app/assets/images/boxroom/fileicons/wav.png +0 -0
  68. data/app/assets/images/boxroom/fileicons/wma.png +0 -0
  69. data/app/assets/images/boxroom/fileicons/wmv.png +0 -0
  70. data/app/assets/images/boxroom/fileicons/xls.png +0 -0
  71. data/app/assets/images/boxroom/fileicons/xlsx.png +0 -0
  72. data/app/assets/images/boxroom/fileicons/xml.png +0 -0
  73. data/app/assets/images/boxroom/fileicons/xvid.png +0 -0
  74. data/app/assets/images/boxroom/fileicons/zip.png +0 -0
  75. data/app/assets/images/boxroom/folder.png +0 -0
  76. data/app/assets/images/boxroom/folder_add.png +0 -0
  77. data/app/assets/images/boxroom/group.png +0 -0
  78. data/app/assets/images/boxroom/group_add.png +0 -0
  79. data/app/assets/images/boxroom/group_grey.png +0 -0
  80. data/app/assets/images/boxroom/information.png +0 -0
  81. data/app/assets/images/boxroom/logo.png +0 -0
  82. data/app/assets/images/boxroom/move.png +0 -0
  83. data/app/assets/images/boxroom/permissions.png +0 -0
  84. data/app/assets/images/boxroom/share.png +0 -0
  85. data/app/assets/images/boxroom/spinner.gif +0 -0
  86. data/app/assets/images/boxroom/tick.png +0 -0
  87. data/app/assets/images/boxroom/user.png +0 -0
  88. data/app/assets/images/boxroom/user_add.png +0 -0
  89. data/app/assets/javascripts/boxroom/application.js.coffee +51 -0
  90. data/app/assets/javascripts/boxroom/files.js.coffee +33 -0
  91. data/app/assets/stylesheets/boxroom/application.scss +7 -0
  92. data/app/concepts/boxroom/base_cell.rb +7 -0
  93. data/app/concepts/boxroom/folder/cell/show.rb +25 -0
  94. data/app/concepts/boxroom/folder/view/show.erb +69 -0
  95. data/app/concepts/boxroom/search/contract/files_and_folders.rb +9 -0
  96. data/app/concepts/boxroom/search/operations/files_and_folders.rb +21 -0
  97. data/app/controllers/boxroom/admins_controller.rb +30 -0
  98. data/app/controllers/boxroom/application_controller.rb +5 -0
  99. data/app/controllers/boxroom/clipboard_controller.rb +87 -0
  100. data/app/controllers/boxroom/files_controller.rb +78 -0
  101. data/app/controllers/boxroom/folders_controller.rb +91 -0
  102. data/app/controllers/boxroom/groups_controller.rb +60 -0
  103. data/app/controllers/boxroom/permissions_controller.rb +19 -0
  104. data/app/controllers/boxroom/reset_password_controller.rb +45 -0
  105. data/app/controllers/boxroom/search_controller.rb +21 -0
  106. data/app/controllers/boxroom/sessions_controller.rb +48 -0
  107. data/app/controllers/boxroom/share_links_controller.rb +67 -0
  108. data/app/controllers/boxroom/signup_controller.rb +31 -0
  109. data/app/controllers/boxroom/users_controller.rb +75 -0
  110. data/app/controllers/concerns/boxroom/base_controller.rb +92 -0
  111. data/app/helpers/boxroom/application_helper.rb +4 -0
  112. data/app/helpers/boxroom/folders_helper.rb +17 -0
  113. data/app/jobs/boxroom/application_job.rb +4 -0
  114. data/app/mailers/boxroom/application_mailer.rb +6 -0
  115. data/app/mailers/boxroom/user_mailer.rb +18 -0
  116. data/app/models/boxroom/application_record.rb +5 -0
  117. data/app/models/boxroom/clipboard.rb +45 -0
  118. data/app/models/boxroom/folder.rb +113 -0
  119. data/app/models/boxroom/group.rb +57 -0
  120. data/app/models/boxroom/permission.rb +6 -0
  121. data/app/models/boxroom/permitted_params.rb +33 -0
  122. data/app/models/boxroom/share_link.rb +40 -0
  123. data/app/models/boxroom/user.rb +113 -0
  124. data/app/models/boxroom/user_file.rb +35 -0
  125. data/app/views/boxroom/admins/new.html.erb +42 -0
  126. data/app/views/boxroom/clipboard/_clipboard_empty.de.html.erb +2 -0
  127. data/app/views/boxroom/clipboard/_clipboard_empty.en.html.erb +2 -0
  128. data/app/views/boxroom/clipboard/_clipboard_empty.es.html.erb +2 -0
  129. data/app/views/boxroom/clipboard/_clipboard_empty.fr.html.erb +2 -0
  130. data/app/views/boxroom/clipboard/_clipboard_empty.it.html.erb +2 -0
  131. data/app/views/boxroom/clipboard/_clipboard_empty.nl.html.erb +2 -0
  132. data/app/views/boxroom/clipboard/_clipboard_empty.zh-CN.html.erb +2 -0
  133. data/app/views/boxroom/clipboard/_show.html.erb +72 -0
  134. data/app/views/boxroom/files/edit.html.erb +24 -0
  135. data/app/views/boxroom/files/new.html.erb +45 -0
  136. data/app/views/boxroom/folders/_form.html.erb +19 -0
  137. data/app/views/boxroom/folders/edit.html.erb +6 -0
  138. data/app/views/boxroom/folders/new.html.erb +6 -0
  139. data/app/views/boxroom/folders/show.html.erb +69 -0
  140. data/app/views/boxroom/groups/_form.html.erb +21 -0
  141. data/app/views/boxroom/groups/edit.html.erb +4 -0
  142. data/app/views/boxroom/groups/index.html.erb +42 -0
  143. data/app/views/boxroom/groups/new.html.erb +4 -0
  144. data/app/views/boxroom/permissions/_form.html.erb +46 -0
  145. data/app/views/boxroom/reset_password/_message.de.html.erb +2 -0
  146. data/app/views/boxroom/reset_password/_message.en.html.erb +2 -0
  147. data/app/views/boxroom/reset_password/_message.es.html.erb +2 -0
  148. data/app/views/boxroom/reset_password/_message.fr.html.erb +2 -0
  149. data/app/views/boxroom/reset_password/_message.it.html.erb +2 -0
  150. data/app/views/boxroom/reset_password/_message.nl.html.erb +2 -0
  151. data/app/views/boxroom/reset_password/_message.zh-CN.html.erb +2 -0
  152. data/app/views/boxroom/reset_password/edit.html.erb +30 -0
  153. data/app/views/boxroom/reset_password/new.html.erb +22 -0
  154. data/app/views/boxroom/search/show.html.erb +15 -0
  155. data/app/views/boxroom/sessions/new.html.erb +31 -0
  156. data/app/views/boxroom/share_links/index.html.erb +24 -0
  157. data/app/views/boxroom/share_links/new.html.erb +49 -0
  158. data/app/views/boxroom/shared/_footer.html.erb +9 -0
  159. data/app/views/boxroom/shared/_header.html.erb +45 -0
  160. data/app/views/boxroom/signup/edit.html.erb +42 -0
  161. data/app/views/boxroom/user_mailer/reset_password_email.de.text.erb +18 -0
  162. data/app/views/boxroom/user_mailer/reset_password_email.en.text.erb +17 -0
  163. data/app/views/boxroom/user_mailer/reset_password_email.es.text.erb +17 -0
  164. data/app/views/boxroom/user_mailer/reset_password_email.fr.text.erb +17 -0
  165. data/app/views/boxroom/user_mailer/reset_password_email.it.text.erb +17 -0
  166. data/app/views/boxroom/user_mailer/reset_password_email.nl.text.erb +17 -0
  167. data/app/views/boxroom/user_mailer/reset_password_email.zh-CN.text.erb +16 -0
  168. data/app/views/boxroom/user_mailer/share_link_email.de.text.erb +20 -0
  169. data/app/views/boxroom/user_mailer/share_link_email.en.text.erb +20 -0
  170. data/app/views/boxroom/user_mailer/share_link_email.es.text.erb +20 -0
  171. data/app/views/boxroom/user_mailer/share_link_email.fr.text.erb +20 -0
  172. data/app/views/boxroom/user_mailer/share_link_email.it.text.erb +20 -0
  173. data/app/views/boxroom/user_mailer/share_link_email.nl.text.erb +20 -0
  174. data/app/views/boxroom/user_mailer/share_link_email.zh-CN.text.erb +20 -0
  175. data/app/views/boxroom/user_mailer/signup_email.de.text.erb +9 -0
  176. data/app/views/boxroom/user_mailer/signup_email.en.text.erb +9 -0
  177. data/app/views/boxroom/user_mailer/signup_email.es.text.erb +9 -0
  178. data/app/views/boxroom/user_mailer/signup_email.fr.text.erb +9 -0
  179. data/app/views/boxroom/user_mailer/signup_email.it.text.erb +9 -0
  180. data/app/views/boxroom/user_mailer/signup_email.nl.text.erb +10 -0
  181. data/app/views/boxroom/user_mailer/signup_email.zh-CN.text.erb +8 -0
  182. data/app/views/boxroom/users/_form.html.erb +63 -0
  183. data/app/views/boxroom/users/edit.html.erb +4 -0
  184. data/app/views/boxroom/users/index.html.erb +68 -0
  185. data/app/views/boxroom/users/new.html.erb +4 -0
  186. data/app/views/layouts/boxroom/application.html.erb +37 -0
  187. data/config/locales/de.yml +414 -0
  188. data/config/locales/en.yml +407 -0
  189. data/config/locales/es.yml +403 -0
  190. data/config/locales/fr.yml +403 -0
  191. data/config/locales/it.yml +414 -0
  192. data/config/locales/nl.yml +408 -0
  193. data/config/locales/zh-CN.yml +406 -0
  194. data/config/routes.rb +44 -0
  195. data/db/migrate/20100930062939_boxroom_create_users.rb +20 -0
  196. data/db/migrate/20100930091426_boxroom_create_folders.rb +14 -0
  197. data/db/migrate/20100930091451_boxroom_create_groups.rb +12 -0
  198. data/db/migrate/20101002122244_boxroom_create_user_files.rb +17 -0
  199. data/db/migrate/20101005071402_boxroom_create_permissions.rb +16 -0
  200. data/db/migrate/20101005071508_boxroom_create_groups_users.rb +12 -0
  201. data/db/migrate/20110106045148_boxroom_drop_column_user_id_from_folders.rb +9 -0
  202. data/db/migrate/20110106045414_boxroom_drop_column_user_id_from_user_files.rb +9 -0
  203. data/db/migrate/20110529123402_boxroom_drop_column_access_key_from_users.rb +9 -0
  204. data/db/migrate/20110616215033_boxroom_create_share_links.rb +15 -0
  205. data/db/migrate/20120411075110_boxroom_add_column_signup_token_to_users.rb +8 -0
  206. data/db/migrate/20120411081345_boxroom_add_column_signup_token_expires_at_to_users.rb +7 -0
  207. data/db/migrate/20130626210927_boxroom_add_columns_message_user_id_to_share_links.rb +6 -0
  208. data/db/migrate/20130628082245_boxroom_populate_user_id_in_share_links.rb +9 -0
  209. data/lib/boxroom.rb +35 -0
  210. data/lib/boxroom/configuration.rb +18 -0
  211. data/lib/boxroom/engine.rb +9 -0
  212. data/lib/boxroom/version.rb +3 -0
  213. data/lib/paperclip/spoof_detector.rb +7 -0
  214. data/lib/tasks/boxroom_tasks.rake +4 -0
  215. metadata +481 -0
@@ -0,0 +1,113 @@
1
+ module Boxroom
2
+ class Folder < ActiveRecord::Base
3
+ acts_as_tree :order => 'name'
4
+
5
+ has_many :user_files, -> {order :attachment_file_name}, :dependent => :destroy
6
+ has_many :permissions, :dependent => :destroy
7
+
8
+ attr_accessor :is_copied_folder
9
+
10
+ validates_uniqueness_of :name, :scope => :parent_id
11
+ validates_presence_of :name
12
+
13
+ before_save :check_for_parent
14
+ after_create :create_permissions, :unless => :is_copied_folder
15
+ before_destroy :dont_destroy_root_folder
16
+
17
+ def copy(target_folder, originally_copied_folder = nil)
18
+ new_folder = self.dup
19
+ new_folder.is_copied_folder = true
20
+ new_folder.parent = target_folder
21
+ new_folder.save!
22
+
23
+ originally_copied_folder = new_folder if originally_copied_folder.nil?
24
+
25
+ # Copy original folder's permissions
26
+ self.permissions.each do |permission|
27
+ new_permission = permission.dup
28
+ new_permission.folder = new_folder
29
+ new_permission.save!
30
+ end
31
+
32
+ self.user_files.each do |file|
33
+ file.copy(new_folder)
34
+ end
35
+
36
+ # Copy sub-folders recursively
37
+ self.children.each do |folder|
38
+ folder.copy(new_folder, originally_copied_folder) unless folder == originally_copied_folder
39
+ end
40
+
41
+ new_folder
42
+ end
43
+
44
+ def move(target_folder)
45
+ unless target_folder == self || self.parent_of?(target_folder)
46
+ self.parent = target_folder
47
+ save!
48
+ else
49
+ raise 'You cannot move a folder to its own sub-folder.'
50
+ end
51
+ end
52
+
53
+ def copy_permissions_to_children(permissions_to_copy)
54
+ permissions_to_copy.each do |permission|
55
+ attributes = permission.attributes.except('id', 'folder_id', 'group_id')
56
+ Permission.where(:folder_id => children, :group_id => permission.group_id).update_all(attributes)
57
+ end
58
+
59
+ # Copy permissions recursively
60
+ children.each do |child|
61
+ child.copy_permissions_to_children(permissions_to_copy) if child.has_children?
62
+ end
63
+ end
64
+
65
+ def parent_of?(folder)
66
+ self.children.each do |child|
67
+ if child == folder
68
+ return true
69
+ else
70
+ return child.parent_of?(folder)
71
+ end
72
+ end
73
+ false
74
+ end
75
+
76
+ def is_root?
77
+ parent.nil? && !new_record?
78
+ end
79
+
80
+ def has_children?
81
+ children.count > 0
82
+ end
83
+
84
+ def self.root
85
+ @root_folder ||= find_by_name_and_parent_id('Root folder', nil)
86
+ end
87
+
88
+ private
89
+
90
+ def check_for_parent
91
+ raise 'Folders must have a parent.' if parent.nil? && name != 'Root folder'
92
+ end
93
+
94
+ def create_permissions
95
+ unless is_root?
96
+ parent.permissions.each do |permission|
97
+ Permission.create! do |p|
98
+ p.group = permission.group
99
+ p.folder = self
100
+ p.can_create = permission.can_create
101
+ p.can_read = permission.can_read
102
+ p.can_update = permission.can_update
103
+ p.can_delete = permission.can_delete
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ def dont_destroy_root_folder
110
+ raise "Can't delete Root folder" if is_root?
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,57 @@
1
+ module Boxroom
2
+ class Group < ActiveRecord::Base
3
+ has_many :permissions, :dependent => :destroy
4
+ has_and_belongs_to_many :users
5
+
6
+ validates_uniqueness_of :name
7
+ validates_presence_of :name
8
+
9
+ after_create :create_admin_permissions, :if => :admins_group?
10
+ after_create :create_permissions, :unless => :admins_group?
11
+ before_destroy :dont_destroy_admins
12
+
13
+ def admins_group?
14
+ name == 'Admins'
15
+ end
16
+
17
+ def self.admins_group
18
+ where(:name => 'Admins').first
19
+ end
20
+
21
+ def self.all_except_admins
22
+ where.not(:name => 'Admins')
23
+ end
24
+
25
+ private
26
+
27
+ def create_admin_permissions
28
+ Folder.find_each do |folder|
29
+ Permission.create! do |p|
30
+ p.group = self
31
+ p.folder = folder
32
+ p.can_create = true
33
+ p.can_read = true
34
+ p.can_update = true
35
+ p.can_delete = true
36
+ end
37
+ end
38
+ end
39
+
40
+ def create_permissions
41
+ Folder.find_each do |folder|
42
+ Permission.create! do |p|
43
+ p.group = self
44
+ p.folder = folder
45
+ p.can_create = false
46
+ p.can_read = folder.is_root? # New groups can read the root folder
47
+ p.can_update = false
48
+ p.can_delete = false
49
+ end
50
+ end
51
+ end
52
+
53
+ def dont_destroy_admins
54
+ raise "Can't delete admins group" if admins_group?
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,6 @@
1
+ module Boxroom
2
+ class Permission < ActiveRecord::Base
3
+ belongs_to :group
4
+ belongs_to :folder
5
+ end
6
+ end
@@ -0,0 +1,33 @@
1
+ module Boxroom
2
+ class PermittedParams < Struct.new(:params, :current_user)
3
+ %w{folder group share_link user user_file}.each do |model_name|
4
+ define_method model_name do
5
+ params.require(model_name.to_sym).permit(*send("#{model_name}_attributes"))
6
+ end
7
+ end
8
+
9
+ def folder_attributes
10
+ [:name]
11
+ end
12
+
13
+ def group_attributes
14
+ [:name]
15
+ end
16
+
17
+ def share_link_attributes
18
+ [:emails, :link_expires_at, :message]
19
+ end
20
+
21
+ def user_attributes
22
+ if current_user && current_user.member_of_admins?
23
+ [:name, :email, :password, :password_confirmation, {:group_ids => []}]
24
+ else
25
+ [:name, :email, :password, :password_confirmation]
26
+ end
27
+ end
28
+
29
+ def user_file_attributes
30
+ [:attachment, :attachment_file_name]
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,40 @@
1
+ module Boxroom
2
+ class ShareLink < ActiveRecord::Base
3
+ belongs_to :user
4
+ belongs_to :user_file
5
+
6
+ validates_presence_of :emails, :link_expires_at
7
+ validates_length_of :emails, :maximum => 255
8
+ validate :format_of_emails
9
+
10
+ before_save :generate_token
11
+
12
+ def self.active_share_links
13
+ where('link_expires_at >= ?', DateTime.now).order(:link_expires_at)
14
+ end
15
+
16
+ def self.file_for_token(token)
17
+ share_link = find_by_link_token(token)
18
+
19
+ if share_link.link_expires_at < DateTime.now
20
+ raise 'This share link expired.'
21
+ else
22
+ share_link.user_file
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def format_of_emails
29
+ emails.split(/,\s*/).each do |email|
30
+ unless email.strip =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/
31
+ errors.add(:emails, I18n.t(:are_invalid_due_to, :email => email))
32
+ end
33
+ end
34
+ end
35
+
36
+ def generate_token
37
+ self.link_token = SecureRandom.hex(10)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,113 @@
1
+ module Boxroom
2
+ class User < ActiveRecord::Base
3
+ has_and_belongs_to_many :groups
4
+ has_many :share_links
5
+
6
+ attr_accessor :password_confirmation, :password_required, :dont_clear_reset_password_token
7
+
8
+ validates_confirmation_of :password
9
+ validates_length_of :password, :in => 6..20, :allow_blank => true
10
+ validates_presence_of :password, :if => :password_required
11
+ validates_presence_of :name, :unless => :new_record?
12
+ validates_presence_of :email
13
+ validates_uniqueness_of :name, :unless => :new_record? && :name_is_blank?
14
+ validates_uniqueness_of :email
15
+ validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/
16
+
17
+ before_create :set_signup_token
18
+ before_save :clear_reset_password_token, :unless => :dont_clear_reset_password_token
19
+ before_update :clear_signup_token
20
+ after_create :create_root_folder_and_admins_group, :if => :is_admin
21
+ before_destroy :dont_destroy_admin
22
+
23
+ %w{create read update delete}.each do |method|
24
+ define_method "can_#{method}" do |folder|
25
+ has_permission = false
26
+
27
+ Permission.where(:group_id => groups, :folder_id => folder.id).each do |permission|
28
+ has_permission = permission.send("can_#{method}")
29
+ break if has_permission
30
+ end
31
+
32
+ has_permission
33
+ end
34
+ end
35
+
36
+ def password
37
+ @password
38
+ end
39
+
40
+ def password=(new_password)
41
+ @password = new_password
42
+
43
+ unless @password.blank?
44
+ self.password_salt = SecureRandom.base64(32)
45
+ self.hashed_password = Digest::SHA256.hexdigest(password_salt + password)
46
+ end
47
+ end
48
+
49
+ def member_of_admins?
50
+ groups.admins_group.present?
51
+ end
52
+
53
+ def refresh_reset_password_token
54
+ self.reset_password_token = SecureRandom.hex(10)
55
+ self.reset_password_token_expires_at = 1.hour.from_now
56
+ self.dont_clear_reset_password_token = true
57
+ save(:validate => false)
58
+ end
59
+
60
+ def refresh_remember_token
61
+ self.remember_token = SecureRandom.base64(32)
62
+ save(:validate => false)
63
+ end
64
+
65
+ def forget_me
66
+ self.remember_token = nil
67
+ save(:validate => false)
68
+ end
69
+
70
+ def name_is_blank?
71
+ self.name.blank?
72
+ end
73
+
74
+ def self.authenticate(name, password)
75
+ return nil if name.blank? || password.blank?
76
+ user = find_by_name(name) or return nil
77
+ hash = Digest::SHA256.hexdigest(user.password_salt + password)
78
+ hash == user.hashed_password ? user : nil
79
+ end
80
+
81
+ def self.no_admin_yet?
82
+ find_by_is_admin(true).blank?
83
+ end
84
+
85
+ private
86
+
87
+ def set_signup_token
88
+ self.signup_token = SecureRandom.hex(10)
89
+ self.signup_token_expires_at = 2.weeks.from_now
90
+ end
91
+
92
+ def clear_signup_token
93
+ unless self.name.blank?
94
+ self.signup_token = nil
95
+ self.signup_token_expires_at = nil
96
+ end
97
+ end
98
+
99
+ def clear_reset_password_token
100
+ self.reset_password_token = nil
101
+ self.reset_password_token_expires_at = nil
102
+ end
103
+
104
+ def create_root_folder_and_admins_group
105
+ Folder.find_or_create_by(name: 'Root folder')
106
+ groups << Group.find_or_create_by(name: 'Admins')
107
+ end
108
+
109
+ def dont_destroy_admin
110
+ raise "Can't delete original admin user" if is_admin
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,35 @@
1
+ module Boxroom
2
+ class UserFile < ActiveRecord::Base
3
+ has_attached_file :attachment, :path => ":rails_root/#{Boxroom.configuration.uploads_path}/:rails_env/:id/:style/:id", :restricted_characters => Boxroom::RESTRICTED_CHARACTERS
4
+ do_not_validate_attachment_file_type :attachment
5
+
6
+ belongs_to :folder
7
+ has_many :share_links, :dependent => :destroy
8
+
9
+ validates_attachment_presence :attachment, :message => I18n.t(:blank, :scope => [:activerecord, :errors, :messages])
10
+ validates_presence_of :folder_id
11
+ validates_uniqueness_of :attachment_file_name, :scope => 'folder_id', :message => I18n.t(:exists_already, :scope => [:activerecord, :errors, :messages])
12
+ validates_format_of :attachment_file_name, :with => /\A[^\/\\\?\*:|"<>]+\z/, :message => I18n.t(:invalid_characters, :scope => [:activerecord, :errors, :messages])
13
+
14
+ def copy(target_folder)
15
+ new_file = self.dup
16
+ new_file.folder = target_folder
17
+ new_file.save!
18
+
19
+ path = "#{Rails.root}/#{Boxroom.configuration.uploads_path}/#{Rails.env}/#{new_file.id}/original"
20
+ FileUtils.mkdir_p path
21
+ FileUtils.cp_r self.attachment.path, "#{path}/#{new_file.id}"
22
+
23
+ new_file
24
+ end
25
+
26
+ def move(target_folder)
27
+ self.folder = target_folder
28
+ save!
29
+ end
30
+
31
+ def extension
32
+ File.extname(attachment_file_name)[1..-1]
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,42 @@
1
+ <% content_for :title, t(:create_admin) -%>
2
+
3
+ <h1 class="title"><%= content_for :title %></h1>
4
+ <div class="notification is-warning">
5
+ <%= t :no_administrator_yet %>
6
+ </div>
7
+ <%= form_for @user, url: {action: 'create'} do |f| %>
8
+ <% if f.error_messages.size > 0 %>
9
+ <div class="notification is-danger">
10
+ <%= f.error_messages %>
11
+ </div>
12
+ <% end %>
13
+ <div class="field">
14
+ <%= f.label :name, t(:username), class: 'label' %>
15
+ <div class="control">
16
+ <%= f.text_field :name, class: 'input' %>
17
+ </div>
18
+ </div>
19
+ <div class="field">
20
+ <%= f.label :email, class: 'label' %>
21
+ <div class="control">
22
+ <%= f.text_field :email, class: 'input' %>
23
+ </div>
24
+ </div>
25
+ <div class="field">
26
+ <%= label_tag :password, class: 'label' %>
27
+ <div class="control">
28
+ <%= f.password_field :password, class: 'input' %>
29
+ </div>
30
+ </div>
31
+ <div class="field">
32
+ <%= label_tag :confirm_password, nil, class: 'label' %>
33
+ <div class="control">
34
+ <%= f.password_field :password_confirmation, class: 'input' %>
35
+ </div>
36
+ </div>
37
+ <div class="field">
38
+ <div class="control">
39
+ <%= f.submit t(:create_admin_account), class: 'button is-link' %>
40
+ </div>
41
+ </div>
42
+ <% end %>