elabs 3.0.0 → 4.0.0

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 (197) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +89 -0
  3. data/Gemfile +1 -1
  4. data/Gemfile.lock +7 -2
  5. data/README.md +24 -17
  6. data/ROADMAP.md +8 -7
  7. data/app/assets/javascripts/elabs/application.js.erb +42 -0
  8. data/app/assets/javascripts/elabs/forms.js +10 -0
  9. data/app/assets/javascripts/elabs/helpers-markdown.js +11 -33
  10. data/app/assets/javascripts/elabs/helpers.js +28 -0
  11. data/app/assets/javascripts/elabs/hljs.js +4 -0
  12. data/app/assets/stylesheets/elabs/_colors.scss +5 -0
  13. data/app/assets/stylesheets/elabs/_fixes.scss +6 -0
  14. data/app/assets/stylesheets/elabs/_icons.scss +4 -0
  15. data/app/assets/stylesheets/elabs/app/_acts.scss +11 -0
  16. data/app/assets/stylesheets/elabs/app/_buttons.scss +8 -0
  17. data/app/assets/stylesheets/elabs/app/_comments.scss +10 -1
  18. data/app/assets/stylesheets/elabs/app/_content.scss +15 -0
  19. data/app/assets/stylesheets/elabs/app/_content_statuses.scss +32 -0
  20. data/app/assets/stylesheets/elabs/app/_forms.scss +5 -0
  21. data/app/assets/stylesheets/elabs/app/_helpers.scss +10 -0
  22. data/app/assets/stylesheets/elabs/app/_layout.scss +4 -0
  23. data/app/assets/stylesheets/elabs/app/_modals.scss +4 -0
  24. data/app/assets/stylesheets/elabs/app/_tables.scss +31 -0
  25. data/app/assets/stylesheets/elabs/app/_typo.scss +14 -0
  26. data/app/assets/stylesheets/elabs/app/_users.scss +14 -6
  27. data/app/assets/stylesheets/elabs/app/admin-members/_forms.scss +8 -1
  28. data/app/assets/stylesheets/elabs/app/admin-members/_indexes.scss +1 -26
  29. data/app/assets/stylesheets/elabs/app/mixins/_content-card.scss +11 -1
  30. data/app/assets/stylesheets/elabs/app/mixins/_content-full.scss +26 -0
  31. data/app/assets/stylesheets/elabs/app/mixins/_content-inline.scss +7 -0
  32. data/app/assets/stylesheets/elabs/app/widgets/_git-cards.scss +88 -0
  33. data/app/assets/stylesheets/elabs/lib/_hljs.scss +5 -0
  34. data/app/assets/stylesheets/elabs/lib/fontawesome/_icons.scss +11 -11
  35. data/app/assets/stylesheets/elabs/lib/knacss/_knacss-variables.scss +10 -2
  36. data/app/assets/stylesheets/elabs/style.scss +11 -1
  37. data/app/controllers/elabs/admin/admin_application_controller.rb +1 -1
  38. data/app/controllers/elabs/admin/admin_content_application_controller.rb +2 -2
  39. data/app/controllers/elabs/admin/languages_controller.rb +1 -1
  40. data/app/controllers/elabs/admin/licenses_controller.rb +1 -1
  41. data/app/controllers/elabs/admin/tags_controller.rb +1 -1
  42. data/app/controllers/elabs/admin/users_controller.rb +1 -1
  43. data/app/controllers/elabs/albums_controller.rb +1 -1
  44. data/app/controllers/elabs/articles_controller.rb +1 -1
  45. data/app/controllers/elabs/content_application_controller.rb +2 -1
  46. data/app/controllers/elabs/elabs_public_controller.rb +28 -8
  47. data/app/controllers/elabs/languages_controller.rb +1 -1
  48. data/app/controllers/elabs/licenses_controller.rb +1 -1
  49. data/app/controllers/elabs/member/albums_controller.rb +1 -1
  50. data/app/controllers/elabs/member/articles_controller.rb +1 -1
  51. data/app/controllers/elabs/member/markdown_previewer_controller.rb +11 -0
  52. data/app/controllers/elabs/member/member_content_application_controller.rb +2 -2
  53. data/app/controllers/elabs/member/notes_controller.rb +1 -1
  54. data/app/controllers/elabs/member/projects_controller.rb +1 -1
  55. data/app/controllers/elabs/member/uploads_controller.rb +1 -1
  56. data/app/controllers/elabs/notes_controller.rb +1 -1
  57. data/app/controllers/elabs/projects_controller.rb +1 -1
  58. data/app/controllers/elabs/tags_controller.rb +1 -6
  59. data/app/controllers/elabs/uploads_controller.rb +1 -1
  60. data/app/controllers/elabs/users_controller.rb +1 -1
  61. data/app/helpers/elabs/acts_helper.rb +2 -2
  62. data/app/helpers/elabs/application_helper.rb +30 -3
  63. data/app/helpers/elabs/content_helper.rb +9 -3
  64. data/app/helpers/elabs/content_renderer_helper.rb +118 -8
  65. data/app/helpers/elabs/rss_helper.rb +9 -0
  66. data/app/helpers/elabs/thumbnails_helper.rb +24 -19
  67. data/app/helpers/elabs/time_helper.rb +7 -1
  68. data/app/models/elabs/album.rb +2 -0
  69. data/app/models/elabs/application_content_record.rb +3 -0
  70. data/app/models/elabs/article.rb +2 -0
  71. data/app/models/elabs/concerns/actable_entity.rb +17 -2
  72. data/app/models/elabs/concerns/content_entity.rb +2 -2
  73. data/app/models/elabs/concerns/sluggable.rb +40 -0
  74. data/app/models/elabs/language.rb +8 -0
  75. data/app/models/elabs/license.rb +5 -0
  76. data/app/models/elabs/note.rb +2 -0
  77. data/app/models/elabs/project.rb +3 -0
  78. data/app/models/elabs/tag.rb +5 -0
  79. data/app/models/elabs/upload.rb +2 -0
  80. data/app/models/elabs/user.rb +10 -2
  81. data/app/views/elabs/acts/_act.rss.builder +22 -0
  82. data/app/views/elabs/acts/index.html.haml +5 -1
  83. data/app/views/elabs/acts/index.rss.builder +15 -0
  84. data/app/views/elabs/admin/albums/index.html.haml +4 -4
  85. data/app/views/elabs/admin/articles/index.html.haml +4 -4
  86. data/app/views/elabs/admin/languages/_form.html.haml +2 -1
  87. data/app/views/elabs/admin/licenses/_form.html.haml +2 -1
  88. data/app/views/elabs/admin/notes/index.html.haml +5 -5
  89. data/app/views/elabs/admin/projects/index.html.haml +4 -4
  90. data/app/views/elabs/admin/reports/index.html.haml +2 -2
  91. data/app/views/elabs/admin/tags/_form.html.haml +2 -1
  92. data/app/views/elabs/admin/uploads/index.html.haml +4 -4
  93. data/app/views/elabs/admin/users/index.html.haml +3 -3
  94. data/app/views/elabs/admin/users/show.html.haml +2 -2
  95. data/app/views/elabs/albums/_album.html.haml +1 -1
  96. data/app/views/elabs/albums/_album.rss.builder +7 -0
  97. data/app/views/elabs/albums/_album_inline.html.haml +8 -0
  98. data/app/views/elabs/albums/index.rss.builder +14 -0
  99. data/app/views/elabs/albums/show.html.haml +3 -3
  100. data/app/views/elabs/articles/_article.html.haml +1 -1
  101. data/app/views/elabs/articles/_article.rss.builder +7 -0
  102. data/app/views/elabs/articles/_article_inline.html.haml +8 -0
  103. data/app/views/elabs/articles/index.rss.builder +14 -0
  104. data/app/views/elabs/articles/show.html.haml +4 -4
  105. data/app/views/elabs/comments/_comments.html.haml +4 -3
  106. data/app/views/elabs/comments/_form.html.haml +18 -6
  107. data/app/views/elabs/languages/_associations.html.haml +15 -5
  108. data/app/views/elabs/layouts/_footer.html.haml +8 -1
  109. data/app/views/elabs/layouts/_hidden_entry.html.haml +4 -4
  110. data/app/views/elabs/layouts/_hidden_entry_full.html.haml +4 -4
  111. data/app/views/elabs/layouts/_hidden_entry_inline.html.haml +6 -0
  112. data/app/views/elabs/layouts/_shortcode_infinite_loop.html.haml +2 -0
  113. data/app/views/elabs/layouts/_shortcode_infinite_loop_inline.html.haml +2 -0
  114. data/app/views/elabs/layouts/_shortcode_missing_content.html.haml +2 -0
  115. data/app/views/elabs/layouts/_shortcode_missing_content_inline.html.haml +2 -0
  116. data/app/views/elabs/layouts/_shortcode_open_to_see.html.haml +2 -0
  117. data/app/views/elabs/layouts/admin_application.html.haml +2 -2
  118. data/app/views/elabs/layouts/application.html.haml +11 -3
  119. data/app/views/elabs/layouts/member_application.html.haml +5 -2
  120. data/app/views/elabs/layouts/widgets/_github_repo_card.html.haml +12 -0
  121. data/app/views/elabs/layouts/widgets/_github_repo_inline.html.haml +8 -0
  122. data/app/views/elabs/layouts/widgets/_github_user_card.html.haml +7 -0
  123. data/app/views/elabs/layouts/widgets/_gitlab_group_card.html.haml +11 -0
  124. data/app/views/elabs/layouts/widgets/_gitlab_repo_card.html.haml +12 -0
  125. data/app/views/elabs/layouts/widgets/_gitlab_repo_inline.html.haml +8 -0
  126. data/app/views/elabs/layouts/widgets/_gitlab_user_card.html.haml +11 -0
  127. data/app/views/elabs/layouts/widgets/vue/_all_widgets.html.haml +5 -0
  128. data/app/views/elabs/layouts/widgets/vue/_github_repo_card_vue.html.haml +72 -0
  129. data/app/views/elabs/layouts/widgets/vue/_github_user_card_vue.html.haml +64 -0
  130. data/app/views/elabs/layouts/widgets/vue/_gitlab_group_card_vue.html.haml +64 -0
  131. data/app/views/elabs/layouts/widgets/vue/_gitlab_repo_card_vue.html.haml +69 -0
  132. data/app/views/elabs/layouts/widgets/vue/_gitlab_user_card_vue.html.haml +99 -0
  133. data/app/views/elabs/licenses/_associations.html.haml +15 -5
  134. data/app/views/elabs/licenses/show.json.jbuilder +1 -1
  135. data/app/views/elabs/member/albums/_form.html.haml +12 -1
  136. data/app/views/elabs/member/albums/index.html.haml +4 -4
  137. data/app/views/elabs/member/articles/_form.html.haml +12 -1
  138. data/app/views/elabs/member/articles/index.html.haml +4 -4
  139. data/app/views/elabs/member/markdown_previewer/preview.json.jbuilder +2 -0
  140. data/app/views/elabs/member/notes/_form.html.haml +12 -1
  141. data/app/views/elabs/member/notes/index.html.haml +4 -4
  142. data/app/views/elabs/member/notifications/index.html.haml +1 -1
  143. data/app/views/elabs/member/preferences/_form.html.haml +2 -1
  144. data/app/views/elabs/member/projects/_form.html.haml +18 -2
  145. data/app/views/elabs/member/projects/_project.json.jbuilder +2 -0
  146. data/app/views/elabs/member/projects/index.html.haml +4 -4
  147. data/app/views/elabs/member/uploads/_form.html.haml +12 -1
  148. data/app/views/elabs/member/uploads/index.html.haml +6 -9
  149. data/app/views/elabs/member/users/_form.html.haml +2 -1
  150. data/app/views/elabs/notes/_note.html.haml +2 -2
  151. data/app/views/elabs/notes/_note.rss.builder +7 -0
  152. data/app/views/elabs/notes/_note_inline.haml +8 -0
  153. data/app/views/elabs/notes/index.rss.builder +14 -0
  154. data/app/views/elabs/notes/show.html.haml +3 -3
  155. data/app/views/elabs/projects/_associations.html.haml +12 -4
  156. data/app/views/elabs/projects/_project.html.haml +1 -1
  157. data/app/views/elabs/projects/_project.json.jbuilder +2 -0
  158. data/app/views/elabs/projects/_project.rss.builder +7 -0
  159. data/app/views/elabs/projects/_project_inline.html.haml +9 -0
  160. data/app/views/elabs/projects/index.rss.builder +14 -0
  161. data/app/views/elabs/projects/show.html.haml +20 -9
  162. data/app/views/elabs/reports/_form.html.haml +2 -1
  163. data/app/views/elabs/tags/_associations.html.haml +15 -5
  164. data/app/views/elabs/tags/index.html.haml +2 -0
  165. data/app/views/elabs/uploads/_preview.html.haml +1 -6
  166. data/app/views/elabs/uploads/_upload.rss.builder +7 -0
  167. data/app/views/elabs/uploads/_upload_inline.html.haml +8 -0
  168. data/app/views/elabs/uploads/index.rss.builder +14 -0
  169. data/app/views/elabs/uploads/show.html.haml +7 -8
  170. data/app/views/elabs/users/_associations.html.haml +15 -5
  171. data/app/views/elabs/users/_user.html.haml +24 -18
  172. data/app/views/elabs/users/_user_inline.html.haml +7 -0
  173. data/app/views/elabs/users/show.html.haml +2 -2
  174. data/config/brakeman.ignore +13 -111
  175. data/config/locales/en.yml +6 -0
  176. data/config/locales/fr.yml +6 -0
  177. data/config/routes.rb +30 -28
  178. data/db/migrate/20180917133442_add_urls_to_projects.rb +6 -0
  179. data/db/migrate/20181005105642_add_reason_to_acts.rb +5 -0
  180. data/db/migrate/20181006073541_add_slugs.rb +39 -0
  181. data/docs/migrating.md +51 -0
  182. data/docs/setup.md +1 -0
  183. data/lib/elabs.rb +5 -0
  184. data/lib/elabs/version.rb +1 -1
  185. data/lib/generators/elabs/install_generator.rb +1 -0
  186. data/lib/generators/elabs/views_generator.rb +0 -1
  187. data/lib/generators/templates/elabs.rb +4 -0
  188. data/lib/generators/templates/user_model.rb +6 -0
  189. data/locale/app.pot +129 -9
  190. data/locale/en/app.edit.po +127 -7
  191. data/locale/en/app.po +127 -7
  192. data/locale/fr/app.edit.po +130 -10
  193. data/locale/fr/app.po +129 -9
  194. metadata +59 -5
  195. data/app/assets/javascripts/elabs/application.js +0 -27
  196. data/app/assets/stylesheets/elabs/app/_nsfw.scss +0 -5
  197. data/lib/assets/javascripts/markdown-it-8.4.2.min.js +0 -1
@@ -12,9 +12,9 @@ module Elabs
12
12
  actions[action.to_sym] || "[missing: #{action}]"
13
13
  end
14
14
 
15
- def act_notice_string(act)
15
+ def act_notice_string(act, include_link = true)
16
16
  string = format('%<type>s #%<id>i', type: act.content_type.demodulize, id: act.content_id)
17
- string = link_to string, act.content unless %w[unpublish destroy lock].include? act.event
17
+ string = link_to string, act.content unless %w[unpublish destroy lock].include?(act.event) || !include_link
18
18
 
19
19
  format(_('%<string>s has been %<event>s'), string: string, event: act_action(act.event)).html_safe
20
20
  end
@@ -1,5 +1,9 @@
1
1
  module Elabs
2
2
  module ApplicationHelper
3
+ def random_string(length = 5)
4
+ [*('a'..'z'), *('0'..'9')].shuffle[0, length].join
5
+ end
6
+
3
7
  def show_nsfw?
4
8
  session[:show_nsfw]
5
9
  end
@@ -19,17 +23,28 @@ module Elabs
19
23
  ).html_safe
20
24
  end
21
25
 
22
- def boolean_icon_tag(value, true_icon = 'check', false_icon = 'times')
26
+ def boolean_icon_tag(value, true_icon = 'check', false_icon = 'times', false_class = '', true_class = '')
23
27
  icon_class = [
24
- "fas fa-#{value ? true_icon : false_icon} fa-fw"
28
+ "fas fa-#{value ? true_icon : false_icon} fa-fw #{value ? true_class : false_class}"
25
29
  ]
26
30
  content_tag(:i, nil, class: icon_class)
27
31
  end
28
32
 
33
+ def colored_good_or_bad_icon_tag(value, true_icon = 'check', false_icon = 'times', false_is_good = false)
34
+ if false_is_good
35
+ false_class = 'is-success'
36
+ true_class = 'is-danger'
37
+ else
38
+ false_class = 'is-danger'
39
+ true_class = 'is-success'
40
+ end
41
+ boolean_icon_tag value, true_icon, false_icon, false_class, true_class
42
+ end
43
+
29
44
  def icon(name, classes = [], base = 'fas')
30
45
  icon_class = ["#{base} fa-#{name}"]
31
46
  icon_class += classes.map do |c|
32
- if %w[2x 3x 4x fw].include? c
47
+ if %w[2x 3x 4x fw pulse spin].include? c
33
48
  "fa-#{c}"
34
49
  else
35
50
  c
@@ -50,5 +65,17 @@ module Elabs
50
65
 
51
66
  out.join('::')
52
67
  end
68
+
69
+ # @author viphe https://stackoverflow.com/users/437585/viphe
70
+ # This method yields a block.
71
+ def with_format(format)
72
+ old_formats = formats
73
+ begin
74
+ self.formats = [format]
75
+ return yield
76
+ ensure
77
+ self.formats = old_formats
78
+ end
79
+ end
53
80
  end
54
81
  end
@@ -1,9 +1,15 @@
1
1
  module Elabs
2
2
  module ContentHelper
3
3
  def show_online_link(entity)
4
- link_to entity,
5
- title: _('View online'),
6
- class: 'btn btn--small btn--show' do
4
+ options = {
5
+ title: _('View online'),
6
+ class: 'btn btn--small btn--show'
7
+ }
8
+ if entity.respond_to?(:publicly_visible?) && !entity.publicly_visible?
9
+ options[:disabled] = true
10
+ return content_tag 'a', icon('eye', ['fw']), options
11
+ end
12
+ link_to entity, options do
7
13
  icon('eye', ['fw'])
8
14
  end
9
15
  end
@@ -1,13 +1,123 @@
1
1
  module Elabs
2
2
  module ContentRendererHelper
3
- ALPHABET = ('a'..'z').to_a
4
-
5
- def markdown(text)
6
- area_id = Array.new(5) { ALPHABET.sample }.join
7
- content = ''.html_safe
8
- content += content_tag('pre', text, id: "raw-#{area_id}")
9
- content += javascript_tag("renderMdFromId('#{area_id}')").html_safe
10
- content_tag('div', content, id: "markdown-#{area_id}").html_safe
3
+ SHORT_CODES = {
4
+ /\[album:(\d+)\]/ => [:shortcode_album, { size: :inline }],
5
+ /\[article:(\d+)\]/ => [:shortcode_article, { size: :inline }],
6
+ /\[note:(\d+)\]/ => [:shortcode_note, { size: :inline }],
7
+ /\[project:(\d+)\]/ => [:shortcode_project, { size: :inline }],
8
+ /\[upload:(\d+)\]/ => [:shortcode_upload, { size: :inline }],
9
+ /\[user:(\d+)\]/ => [:shortcode_user, { size: :inline }],
10
+ /\[album-card:(\d+)\]/ => [:shortcode_album, { size: :large }],
11
+ /\[article-card:(\d+)\]/ => [:shortcode_article, { size: :large }],
12
+ /\[note-card:(\d+)\]/ => [:shortcode_note, { size: :large }],
13
+ /\[project-card:(\d+)\]/ => [:shortcode_project, { size: :large }],
14
+ /\[upload-card:(\d+)\]/ => [:shortcode_upload, { size: :large }],
15
+ /\[user-card:(\d+)\]/ => [:shortcode_user, { size: :large }],
16
+ %r{\[github-repo:([a-zA-Z0-9\-_]+/[a-zA-Z0-9\-_]+)\]} => [:shortcode_github_repo_inline, { size: :inline }],
17
+ %r{\[github-repo-card:([a-zA-Z0-9\-_]+/[a-zA-Z0-9\-_]+)\]} => [:shortcode_github_repo, {}],
18
+ /\[github-user-card:([a-zA-Z0-9\-_]+)\]/ => [:shortcode_github_user, {}],
19
+ %r{\[gitlab-repo:(https://.*)\]} => [:shortcode_gitlab_repo_inline, { size: :inline }],
20
+ %r{\[gitlab-repo-card:(https://.*)\]} => [:shortcode_gitlab_repo, {}],
21
+ %r{\[gitlab-user-card:(https://.*)\]} => [:shortcode_gitlab_user, {}],
22
+ %r{\[gitlab-group-card:(https://.*)\]} => [:shortcode_gitlab_group, {}]
23
+ }.freeze
24
+
25
+ def markdown(text, reference_entity = nil, show_short_codes = true)
26
+ process_short_codes CommonMarker.render_html(text, [:SAFE], [:table]).html_safe,
27
+ reference_entity,
28
+ show_short_codes
29
+ end
30
+
31
+ def render_entity_content(entity, field, show_short_codes = true)
32
+ markdown entity[field], entity, show_short_codes
33
+ end
34
+
35
+ def process_short_codes(text, original_entity = nil, display = true)
36
+ SHORT_CODES.each do |key, method|
37
+ text.gsub! key do |match|
38
+ if display || (method[1][:size] && method[1][:size] == :inline)
39
+ send(method[0], original_entity, match.sub(key, '\1'), method[1])
40
+ else
41
+ render(partial: 'elabs/layouts/shortcode_open_to_see') unless display
42
+ end
43
+ end
44
+ end
45
+ text.html_safe
46
+ end
47
+
48
+ private
49
+
50
+ def shortcode_album(original_entity, id, options = {})
51
+ shortcode_content 'album', original_entity, id, options
52
+ end
53
+
54
+ def shortcode_article(original_entity, id, options = {})
55
+ shortcode_content 'article', original_entity, id, options
56
+ end
57
+
58
+ def shortcode_note(original_entity, id, options = {})
59
+ shortcode_content 'note', original_entity, id, options
60
+ end
61
+
62
+ def shortcode_project(original_entity, id, options = {})
63
+ shortcode_content 'project', original_entity, id, options
64
+ end
65
+
66
+ def shortcode_upload(original_entity, id, options = {})
67
+ shortcode_content 'upload', original_entity, id, options
68
+ end
69
+
70
+ def shortcode_user(original_entity, id, options = {})
71
+ shortcode_content 'user', original_entity, id, options
72
+ end
73
+
74
+ def shortcode_content(type, original_entity, id, options = { size: :large })
75
+ model = "Elabs::#{type.classify}".constantize
76
+ widget_size = case options[:size]
77
+ when :inline
78
+ '_inline'
79
+ else
80
+ ''
81
+ end
82
+ return render "elabs/layouts/shortcode_infinite_loop#{widget_size}", format: :html if original_entity && original_entity.id == id.to_i && original_entity.class == model
83
+
84
+ entity = model.find_by(id: id)
85
+ return render "elabs/layouts/shortcode_missing_content#{widget_size}", format: :html unless entity
86
+
87
+ render partial: "elabs/#{type.pluralize}/#{type}#{widget_size}", locals: { type.to_sym => entity }, format: :html
88
+ end
89
+
90
+ def shortcode_github_repo(_original_entity, repo_url, _options = {})
91
+ render partial: 'elabs/layouts/widgets/github_repo_card', locals: { repo_url: repo_url }
92
+ end
93
+
94
+ def shortcode_github_repo_inline(_original_entity, repo_url, _options = {})
95
+ url_matches = %r{([a-zA-Z0-9\-_]+)/([a-zA-Z0-9\-_]+)}.match repo_url
96
+ render partial: 'elabs/layouts/widgets/github_repo_inline', locals: { url_matches: url_matches }
97
+ end
98
+
99
+ def shortcode_github_user(_original_entity, user_name, _options = {})
100
+ render partial: 'elabs/layouts/widgets/github_user_card', locals: { user_name: user_name }
101
+ end
102
+
103
+ def shortcode_gitlab_repo(_original_entity, repo_url, _options = {})
104
+ url_matches = %r{(?:https://)?([a-z0-9\-_\.]+)/(.+)}.match repo_url
105
+ render partial: 'elabs/layouts/widgets/gitlab_repo_card', locals: { url_matches: url_matches }
106
+ end
107
+
108
+ def shortcode_gitlab_repo_inline(_original_entity, repo_url, _options = {})
109
+ url_matches = %r{(.*)/([a-zA-Z0-9\-_]+)/([a-zA-Z0-9\-_]+)}.match repo_url
110
+ render partial: 'elabs/layouts/widgets/gitlab_repo_inline', locals: { url_matches: url_matches }
111
+ end
112
+
113
+ def shortcode_gitlab_user(_original_entity, user_url, _options = {})
114
+ url_matches = %r{(?:https://)?([a-z0-9\-_\.]*)/([a-zA-Z0-9\-_]+)}.match user_url
115
+ render partial: 'elabs/layouts/widgets/gitlab_user_card', locals: { url_matches: url_matches }
116
+ end
117
+
118
+ def shortcode_gitlab_group(_original_entity, group_url, _options = {})
119
+ url_matches = %r{(?:https://)?([a-z0-9\-_\.]*)/([a-zA-Z0-9\-_]+)}.match group_url
120
+ render partial: 'elabs/layouts/widgets/gitlab_group_card', locals: { url_matches: url_matches }
11
121
  end
12
122
  end
13
123
  end
@@ -0,0 +1,9 @@
1
+ module Elabs
2
+ module RssHelper
3
+ def rss_title(entity, field)
4
+ sfw = entity.sfw ? '[SFW]' : '[NSFW]'
5
+ language = "[#{entity.language.iso639_1}]"
6
+ "#{language} #{sfw} - #{entity[field]}"
7
+ end
8
+ end
9
+ end
@@ -1,13 +1,20 @@
1
1
  module Elabs
2
2
  module ThumbnailsHelper
3
- def thumbnail_center_crop_properties(size = :medium)
4
- dimensions = case size
5
- when :small
6
- '50x50'
7
- else
8
- '300x300' # medium size
9
- end
10
- { gravity: 'Center', resize: "#{dimensions}^", extent: dimensions }
3
+ THUMBNAILS_DIMENSIONS = {
4
+ small: '50x50',
5
+ medium: '300x300'
6
+ }.freeze
7
+
8
+ AVATAR_DIMENSIONS = {
9
+ large: '512',
10
+ medium: '256',
11
+ small: '64'
12
+ }.freeze
13
+
14
+ def thumbnail_center_crop(document, size = :medium)
15
+ return resize_and_center_crop(document, AVATAR_DIMENSIONS[size]) if document.representable?
16
+
17
+ thumbnail_preview_placeholder_file
11
18
  end
12
19
 
13
20
  def thumbnail_preview_placeholder_file
@@ -26,18 +33,16 @@ module Elabs
26
33
  end
27
34
 
28
35
  def avatar_image(avatar, size = :medium)
29
- x = avatar.blob.metadata[:width].to_f
30
- y = avatar.blob.metadata[:height].to_f
36
+ resize_and_center_crop avatar, AVATAR_DIMENSIONS[size]
37
+ end
38
+
39
+ def resize_and_center_crop(entity, size)
40
+ x = entity.blob.metadata[:width].to_f
41
+ y = entity.blob.metadata[:height].to_f
31
42
  bigger_size = x < y ? x : y
32
- dimensions = case size
33
- when :large
34
- '512'
35
- when :medium
36
- '256'
37
- when :small
38
- '64'
39
- end
40
- avatar.variant(combine_options: { gravity: 'center', crop: "#{bigger_size}x#{bigger_size}+0+0", resize: dimensions.to_s }).processed
43
+
44
+ options = { combine_options: { gravity: 'center', crop: "#{bigger_size}x#{bigger_size}+0+0", resize: size.to_s } }
45
+ main_app.url_for(entity.representation(options).processed)
41
46
  end
42
47
  end
43
48
  end
@@ -20,7 +20,13 @@ module Elabs
20
20
  def short_date(date)
21
21
  return nil if date.nil?
22
22
 
23
- I18n.l date, format: :short
23
+ I18n.l date.to_date, format: :default
24
+ end
25
+
26
+ def medium_datetime(date)
27
+ return nil if date.nil?
28
+
29
+ I18n.l date, format: :medium
24
30
  end
25
31
  end
26
32
  end
@@ -2,12 +2,14 @@ module Elabs
2
2
  class Album < ApplicationContentRecord
3
3
  self.table_name = 'albums'
4
4
 
5
+ SLUGGABLE_FIELD = :name
5
6
  ADDITIONAL_HABTM_COUNTER_CACHES = [
6
7
  %w[projects albums]
7
8
  ].freeze
8
9
 
9
10
  validates :name, presence: true
10
11
  validates :description, presence: true
12
+ validates :slug, presence: true, uniqueness: true
11
13
  validates_with AssociatedAuthorValidator, relations: %w[project upload]
12
14
 
13
15
  belongs_to :user
@@ -5,6 +5,9 @@ module Elabs
5
5
  include Elabs::Concerns::CountableEntity
6
6
  include Elabs::Concerns::NotifiableEntity
7
7
  include Elabs::Concerns::Taggable
8
+ include Elabs::Concerns::Sluggable
9
+
10
+ SLUG_FIELD = :slug
8
11
 
9
12
  self.abstract_class = true
10
13
  end
@@ -2,6 +2,7 @@ module Elabs
2
2
  class Article < ApplicationContentRecord
3
3
  self.table_name = 'articles'
4
4
 
5
+ SLUGGABLE_FIELD = :title
5
6
  ADDITIONAL_HABTM_COUNTER_CACHES = [
6
7
  %w[projects articles]
7
8
  ].freeze
@@ -9,6 +10,7 @@ module Elabs
9
10
  validates :title, presence: true
10
11
  validates :excerpt, presence: true
11
12
  validates :content, presence: true
13
+ validates :slug, presence: true, uniqueness: true
12
14
  validates_with AssociatedAuthorValidator, relations: %w[project]
13
15
 
14
16
  belongs_to :user
@@ -4,6 +4,9 @@ module Elabs
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  included do
7
+ attr_accessor :update_description
8
+ attr_reader :minor_update
9
+
7
10
  has_many :acts, as: :content
8
11
 
9
12
  before_save :update_acts?
@@ -12,10 +15,21 @@ module Elabs
12
15
  before_destroy :update_acts_on_delete
13
16
  end
14
17
 
18
+ def minor_update=(value)
19
+ @minor_update = ['t', '1', 1, true].include? value
20
+ end
21
+
22
+ def minor_update?
23
+ @minor_update || false
24
+ end
25
+
15
26
  private
16
27
 
17
28
  def update_acts?
18
- @action = if changed.include?('published')
29
+ # byebug
30
+ @action = if minor_update?
31
+ :nothing
32
+ elsif changed.include?('published')
19
33
  current_publish_action
20
34
  elsif changed.include?('locked') && published?
21
35
  current_lock_action
@@ -28,7 +42,8 @@ module Elabs
28
42
 
29
43
  def update_acts
30
44
  acts.destroy_all if %i[lock unpublish].include? @action
31
- Act.create content: self, event: @action unless @action == :nothing || hidden_in_history
45
+ reason = update_description.nil? ? nil : update_description
46
+ Act.create content: self, event: @action, reason: reason unless @action == :nothing || hidden_in_history
32
47
  end
33
48
 
34
49
  # TODO: check if used ? (dependent: destroy may do the trick.)
@@ -80,8 +80,8 @@ module Elabs
80
80
  end
81
81
 
82
82
  class_methods do
83
- def find_publicly_visible(id)
84
- entity = where(id: id).published.first
83
+ def find_publicly_visible(slug)
84
+ entity = where(slug: slug).published.first
85
85
 
86
86
  raise ActiveRecord::RecordNotFound if entity.nil?
87
87
 
@@ -0,0 +1,40 @@
1
+ module Elabs
2
+ module Concerns
3
+ # For this concern to work, a SLUGGABLE_FIELD constant should be declared in the model
4
+ module Sluggable
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ before_validation :fill_slug, on: :create
9
+ end
10
+
11
+ def fill_slug
12
+ return unless self.class::SLUGGABLE_FIELD
13
+
14
+ slug = make_slug_from_field
15
+ slug_field = self.class::SLUG_FIELD || :slug
16
+
17
+ same_slugs = self.class
18
+ .where("#{slug_field} LIKE ?", "#{slug}%")
19
+ .pluck(slug_field)
20
+ .count { |r| r[/^#{slug}(-\d+)?$/] }
21
+
22
+ slug += "-#{same_slugs}" if same_slugs.positive?
23
+
24
+ self.slug = slug
25
+ end
26
+
27
+ def to_param
28
+ slug
29
+ end
30
+
31
+ private
32
+
33
+ def make_slug_from_field
34
+ return Time.new.strftime('%Y-%m-%d-%H-%M-%S') if self.class::SLUGGABLE_FIELD == :created_at
35
+
36
+ send(self.class::SLUGGABLE_FIELD).parameterize
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,6 +1,10 @@
1
1
  module Elabs
2
2
  class Language < ApplicationRecord
3
3
  self.table_name = 'languages'
4
+ include Elabs::Concerns::Sluggable
5
+
6
+ SLUGGABLE_FIELD = nil
7
+ SLUG_FIELD = :iso639_1
4
8
 
5
9
  validates :iso639_1, presence: true
6
10
  validates :name, presence: true
@@ -14,5 +18,9 @@ module Elabs
14
18
  scope :with_content_only, -> { where.not(albums_count: 0).or(where.not(articles_count: 0)).or(where.not(notes_count: 0)).or(where.not(projects_count: 0)).or(where.not(uploads_count: 0)) }
15
19
  scope :available_site_translations, -> { select(:id, :name, :iso639_1).where(iso639_1: I18n.available_locales) }
16
20
  scope :for_list, -> { order(:name).pluck(:name, :id) }
21
+
22
+ def to_param
23
+ iso639_1
24
+ end
17
25
  end
18
26
  end