biovision-base 0.15.180502 → 0.17.180619

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/biovision/base/placeholders/user.svg +4 -21
  3. data/app/assets/javascripts/biovision/base/biovision-sliders.js +24 -1
  4. data/app/assets/javascripts/biovision/base/biovision.js +27 -5
  5. data/app/assets/stylesheets/biovision/base/biovision.scss +8 -1
  6. data/app/assets/stylesheets/biovision/base/default.scss +13 -5
  7. data/app/controllers/about_controller.rb +8 -3
  8. data/app/controllers/admin/editable_pages_controller.rb +3 -1
  9. data/app/controllers/editable_pages_controller.rb +1 -5
  10. data/app/controllers/fallback_controller.rb +11 -0
  11. data/app/controllers/media_files_controller.rb +9 -1
  12. data/app/controllers/my/profiles_controller.rb +6 -1
  13. data/app/models/concerns/checkable.rb +20 -0
  14. data/app/models/editable_page.rb +27 -10
  15. data/app/models/feedback_request.rb +4 -3
  16. data/app/models/foreign_site.rb +7 -4
  17. data/app/models/media_file.rb +0 -1
  18. data/app/models/privilege.rb +2 -2
  19. data/app/models/user.rb +4 -4
  20. data/app/views/about/contact.html.erb +24 -0
  21. data/app/views/admin/editable_pages/entity/_in_list.html.erb +16 -0
  22. data/app/views/admin/editable_pages/index.html.erb +1 -1
  23. data/app/views/admin/editable_pages/show.html.erb +10 -1
  24. data/app/views/admin/index/_biovision_base.html.erb +1 -0
  25. data/app/views/admin/users/entity/_custom_nav.html.erb +0 -0
  26. data/app/views/admin/users/entity/_in_list.html.erb +19 -3
  27. data/app/views/admin/users/show.html.erb +18 -9
  28. data/app/views/application/error.jbuilder +3 -0
  29. data/app/views/editable_pages/_editable_page.html.erb +2 -4
  30. data/app/views/editable_pages/_form.html.erb +50 -11
  31. data/app/views/editable_pages/edit.html.erb +3 -3
  32. data/app/views/editable_pages/entity/_content.html.erb +11 -0
  33. data/app/views/editable_pages/entity/_metadata.html.erb +1 -4
  34. data/app/views/fallback/show.html.erb +1 -0
  35. data/app/views/feedback_requests/_form.html.erb +38 -27
  36. data/app/views/my/profiles/check.jbuilder +4 -0
  37. data/app/views/my/profiles/new/_form.html.erb +11 -10
  38. data/app/views/shared/_meta_texts.html.erb +26 -12
  39. data/app/views/shared/forms/_entity_flags.html.erb +11 -0
  40. data/app/views/shared/forms/_wysiwyg.html.erb +1 -1
  41. data/app/views/shared/forms/check.jbuilder +4 -0
  42. data/app/views/users/_form.html.erb +32 -39
  43. data/config/locales/common-en.yml +6 -4
  44. data/config/locales/common-ru.yml +7 -4
  45. data/config/locales/editable-pages-ru.yml +12 -4
  46. data/config/locales/feedback-en.yml +6 -1
  47. data/config/locales/feedback-ru.yml +5 -5
  48. data/config/locales/users-en.yml +1 -0
  49. data/config/locales/users-ru.yml +1 -0
  50. data/config/routes.rb +11 -2
  51. data/db/migrate/20170302000101_create_privileges.rb +1 -0
  52. data/db/migrate/20170320000000_create_editable_pages.rb +25 -12
  53. data/db/migrate/20171211000000_create_feedback_requests.rb +7 -1
  54. data/db/migrate/20180610222222_add_consent_to_feedback_requests.rb +15 -0
  55. data/db/migrate/20180612111111_add_administrative_to_privilege.rb +11 -0
  56. data/db/migrate/20180619121212_add_image_alt_text_to_editable_page.rb +11 -0
  57. data/lib/biovision/base/base_methods.rb +3 -2
  58. data/lib/biovision/base/version.rb +1 -1
  59. metadata +15 -4
  60. data/db/migrate/20171025222222_add_new_fields_171026.rb +0 -21
  61. data/db/migrate/20171217222222_add_fields_to_feedback_requests.rb +0 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2a1498261b5c92964dc68ed231731b1edbe106d0b41e1cae16c10527ec1891d4
4
- data.tar.gz: e4968f3a7396a9d54d95840ea4435a6198c85a12db44519b06738e7261c12016
3
+ metadata.gz: d27941a438886a58f345aa63fc7cb640322245be245db3ce049955f2c5e5c63c
4
+ data.tar.gz: dd9e9b5ec6f04673bc2946b6aeca0b0ac0235df23b83e32771553e995e6f2f53
5
5
  SHA512:
6
- metadata.gz: 1b96d1c6787eea0003c5e8d0c5341385761a75348944d9d7212ef31e7b03b9575ff43b8feb88b648d1e492abde88549bb12a41724714ca456be99b0020edc1be
7
- data.tar.gz: f35baf097a33a05fa6c1deaf62823a92657942f40f7e0bdd41dfd832869cad03b17a57d7af2bf2fa9c0d2643ab4ea28d19b1a9e90609b90af6c02a6cee1d2751
6
+ metadata.gz: ef9c838486e81589fb35a1cbf066f7d19d91c0147084360ab7cd5fdbab460898b3adca97d3805ea03547864021d3d5fa091dfe368ced7691ac19436d8b46e806
7
+ data.tar.gz: 5ab35349100232156ac728f4f6d08a0c785529a7d414c8764f46d05d3aca1e57aaaea71416afb0063c3b495a0b32546695a5832a32c69da0f55c68318e3e2cd0
@@ -1,21 +1,4 @@
1
- <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="480px" height="480px" viewBox="-216 -216 480 480">
2
- <path d="M23.25,259C-106.952,259-212.5,153.446-212.5,23.25c0-130.204,105.548-235.75,235.75-235.75
3
- C153.446-212.5,259-106.954,259,23.25C259,153.446,153.446,259,23.25,259z M153.842,191.643c-1.751-2.588-3.987-5.811-5.767-8.333
4
- c-3.114-4.428-6.227-8.835-9.011-13.221c-0.133-0.197-15.5-20.829-70.909-23.351c-19.272,0-33.282-14.461-33.316-34.425
5
- l-0.361-10.48c0-1.514-0.177,1.666,0,0V90.606L45.704,79.38c8.2-3.803,18.638-10.206,26.88-16.433l1.522-1.041
6
- c6.525-4.145,15.635-12.871,16.501-16.205l0.406-4.275c4.188-21.59,10.82-60.861,10.82-74.308c0-52.874-25.71-78.583-78.584-78.583
7
- c-53.604,0-78.583,24.969-78.583,78.583c0,13.809,6.633,52.886,10.81,74.264l0.394,3.97c0.708,3.507,8.969,11.818,16.27,16.399
8
- l1.097,0.703c8.847,6.183,19.421,13.068,27.56,16.926l11.227,11.227v11.227c0.158,1.557,0-1.645,0,0l-0.373,10.48
9
- c0,19.932-13.983,34.402-32.364,34.402c-0.01,0-0.021,0-0.033,0c-55.637,2.259-71.77,23.307-71.791,23.307
10
- c-2.83,4.452-5.927,8.859-9.062,13.31c-1.759,2.5-3.985,5.723-5.755,8.311c36.111,28.044,81.33,44.903,130.591,44.903
11
- C72.499,236.546,117.729,219.687,153.842,191.643z M23.25-190.049c-117.797,0-213.297,95.5-213.297,213.299
12
- c0,60.472,25.259,114.915,65.674,153.725c4.287-6.338,8.87-12.674,12.909-19.011c0,0,18.748-30.796,89.811-33.679
13
- c7.241,0,10.854-4.735,10.854-11.972h0.011c-0.011-5.843-0.011-10.48-0.011-10.48c0-1.458-0.237-2.774-0.303-4.188
14
- c-8.129-3.837-17.557-9.144-28.503-16.773c0,0-26.942-16.576-26.942-35.171c0,0-11.226-57.429-11.226-78.583
15
- c0-52.134,22.293-101.035,101.036-101.035c77.684,0,101.035,48.9,101.035,101.035c0,20.634-11.228,78.583-11.228,78.583
16
- c0,18.09-26.937,35.171-26.937,35.171c-10.721,8.091-20.226,13.495-28.545,17.365c-0.067,1.216-0.265,2.347-0.265,3.596
17
- c0,0-0.012,4.638-0.012,10.48h0.012c-0.021,7.236,3.597,11.972,10.832,11.972c72.114,3.234,89.808,33.679,89.808,33.679
18
- c4.036,6.337,8.618,12.673,12.893,19.011c40.425-38.81,65.691-93.253,65.691-153.725C236.547-94.549,141.05-190.049,23.25-190.049z"
19
- fill="#aaa"
20
- />
21
- </svg>
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <svg version="1.1" x="0px" y="0px" width="80px" height="80px" viewBox="0 0 80 80" xmlns="http://www.w3.org/2000/svg" xmlns:bx="https://boxy-svg.com">
3
+ <path d="M 40 80 C 17.908 80 0 62.091 0 40 C 0 17.908 17.908 0 40 0 C 62.091 0 80 17.908 80 40 C 80 62.091 62.091 80 40 80 Z M 62.158 68.571 C 61.861 68.132 61.481 67.585 61.179 67.158 C 60.651 66.406 60.123 65.659 59.65 64.914 C 59.628 64.881 57.02 61.38 47.619 60.952 C 44.349 60.952 41.972 58.499 41.966 55.111 L 41.905 53.333 C 41.905 53.076 41.875 53.616 41.905 53.333 L 41.905 51.428 L 43.81 49.524 C 45.201 48.878 46.972 47.792 48.371 46.735 L 48.629 46.559 C 49.736 45.856 51.282 44.375 51.429 43.809 L 51.497 43.084 C 52.208 39.421 53.333 32.758 53.333 30.476 C 53.333 21.505 48.971 17.143 40 17.143 C 30.905 17.143 26.667 21.379 26.667 30.476 C 26.667 32.819 27.792 39.449 28.501 43.076 L 28.568 43.75 C 28.688 44.345 30.089 45.755 31.328 46.533 L 31.514 46.652 C 33.015 47.701 34.809 48.869 36.19 49.524 L 38.095 51.429 L 38.095 53.333 C 38.122 53.598 38.095 53.054 38.095 53.333 L 38.032 55.112 C 38.032 58.493 35.659 60.949 32.541 60.949 C 32.539 60.949 32.537 60.949 32.535 60.949 C 23.095 61.332 20.358 64.903 20.354 64.903 C 19.874 65.659 19.349 66.406 18.817 67.161 C 18.518 67.586 18.141 68.133 17.84 68.572 C 23.967 73.33 31.64 76.19 39.998 76.19 C 48.356 76.19 56.03 73.33 62.158 68.571 Z M 40 3.809 C 20.013 3.809 3.81 20.013 3.81 40 C 3.81 50.26 8.095 59.498 14.953 66.083 C 15.68 65.007 16.458 63.932 17.143 62.857 C 17.143 62.857 20.324 57.632 32.381 57.143 C 33.61 57.143 34.223 56.339 34.223 55.111 L 34.225 55.111 C 34.223 54.12 34.223 53.333 34.223 53.333 C 34.223 53.086 34.183 52.863 34.171 52.623 C 32.792 51.972 31.193 51.071 29.335 49.777 C 29.335 49.777 24.764 46.964 24.764 43.809 C 24.764 43.809 22.859 34.065 22.859 30.476 C 22.859 21.63 26.642 13.333 40.002 13.333 C 53.183 13.333 57.145 21.63 57.145 30.476 C 57.145 33.977 55.24 43.809 55.24 43.809 C 55.24 46.879 50.669 49.777 50.669 49.777 C 48.85 51.15 47.238 52.067 45.826 52.723 C 45.815 52.929 45.781 53.121 45.781 53.333 C 45.781 53.333 45.779 54.12 45.779 55.111 L 45.781 55.111 C 45.778 56.339 46.392 57.143 47.619 57.143 C 59.855 57.691 62.857 62.857 62.857 62.857 C 63.542 63.932 64.319 65.007 65.044 66.083 C 71.903 59.498 76.19 50.26 76.19 40 C 76.19 20.013 59.987 3.809 40 3.809 Z" fill="#aaa" bx:origin="0 0"/>
4
+ </svg>
@@ -23,7 +23,30 @@ Biovision.sliders = {
23
23
  li.style.opacity = '0';
24
24
  setTimeout(move, delay);
25
25
  }
26
- }
26
+ },
27
+ slide: {
28
+ left: function (list, delay) {
29
+ const li = list.querySelector('li:last-of-type');
30
+ const elementWidth = li.offsetWidth;
31
+ const restore_style = function () {
32
+ li.style.marginLeft = '';
33
+ };
34
+
35
+ li.style.marginLeft = -elementWidth + 'px';
36
+ list.prepend(li);
37
+ setTimeout(restore_style, delay);
38
+ },
39
+ right: function (list, delay) {
40
+ const li = list.querySelector('li:first-of-type');
41
+ const elementWidth = li.offsetWidth;
42
+ const move = function () {
43
+ list.append(li);
44
+ li.style.marginLeft = '';
45
+ };
46
+ li.style.marginLeft = -elementWidth + 'px';
47
+ setTimeout(move, delay);
48
+ }
49
+ },
27
50
  },
28
51
  initialize: function (slider) {
29
52
  const delay = slider.getAttribute('data-delay') || 125;
@@ -100,6 +100,13 @@ const Biovision = {
100
100
 
101
101
  return request;
102
102
  },
103
+ jsonAjaxRequest: function (method, url, onSuccess, onFailure) {
104
+ const request = Biovision.new_ajax_request(method, url, onSuccess, onFailure);
105
+
106
+ request.setRequestHeader('Content-Type', 'application/json');
107
+
108
+ return request;
109
+ },
103
110
  handle_ajax_failure: function (response) {
104
111
  console.log('AJAX failed', this);
105
112
  if (response.hasOwnProperty('responseJSON')) {
@@ -187,7 +194,7 @@ const Biovision = {
187
194
  const errors = response.meta.errors;
188
195
 
189
196
  if (errors.hasOwnProperty(key)) {
190
- container.innerHTML = errors[key];
197
+ container.innerHTML = errors[key].join('; ');
191
198
  container.classList.remove('hidden');
192
199
  } else {
193
200
  container.classList.add('hidden');
@@ -198,12 +205,27 @@ const Biovision = {
198
205
  }
199
206
  });
200
207
 
201
- request.send(new FormData(form));
208
+ const data = new window.FormData();
209
+ Array.from((new FormData(form)).entries()).forEach(function (entry) {
210
+ const value = entry[1];
211
+
212
+ if (value instanceof window.File && value.name === '' && value.size === 0) {
213
+ data.append(entry[0], new window.Blob([]), '');
214
+ } else {
215
+ if (entry[0] !== '_method') {
216
+ data.append(entry[0], value);
217
+ }
218
+ }
219
+ });
220
+
221
+ request.send(data);
202
222
  };
203
223
 
204
- form.querySelectorAll('[data-check]').forEach(function (element) {
205
- element.addEventListener('blur', perform_check);
206
- });
224
+ if (url.length) {
225
+ form.querySelectorAll('[data-check]').forEach(function (element) {
226
+ element.addEventListener('blur', perform_check);
227
+ });
228
+ }
207
229
  },
208
230
  show_list_of_errors: function (entity_name, list) {
209
231
  const form = document.getElementById(entity_name + '-form');
@@ -4,6 +4,7 @@
4
4
 
5
5
  html {
6
6
  font: 10px $font-family-main;
7
+ height: 100%;
7
8
  margin: 0;
8
9
  padding: 0;
9
10
  -webkit-text-size-adjust: none;
@@ -58,7 +59,7 @@ article {
58
59
  button,
59
60
  input,
60
61
  textarea {
61
- font-size: $font-size-normal;
62
+ font-size: inherit;
62
63
  }
63
64
 
64
65
  ul.actions {
@@ -307,10 +308,12 @@ form {
307
308
 
308
309
  > * {
309
310
  bottom: 0;
311
+ height: 100%;
310
312
  left: 0;
311
313
  position: absolute;
312
314
  right: 0;
313
315
  top: 0;
316
+ width: 100%;
314
317
  }
315
318
 
316
319
  &::before {
@@ -342,3 +345,7 @@ form {
342
345
  padding-top: 50%;
343
346
  }
344
347
  }
348
+
349
+ input.control:not(:checked) + div {
350
+ display: none;
351
+ }
@@ -1,11 +1,11 @@
1
1
  $font-family-main: "Roboto", sans-serif !default;
2
2
  $font-family-heading: $font-family-main !default;
3
3
 
4
- $font-size-large: 2rem !default;
5
- $font-size-increased: 1.6rem !default;
6
- $font-size-normal: 1.4rem !default;
7
- $font-size-decreased: 1.2rem !default;
8
- $font-size-small: 1rem !default;
4
+ $font-size-large: 2.4rem !default;
5
+ $font-size-increased: 1.8rem !default;
6
+ $font-size-normal: 1.6rem !default;
7
+ $font-size-decreased: 1.3rem !default;
8
+ $font-size-small: 1.1rem !default;
9
9
 
10
10
  $content-width: 100rem !default;
11
11
  $content-width-min: 32rem !default;
@@ -32,3 +32,11 @@ $background-footer: #fff !default;
32
32
  $link-color: rgb(20, 127, 255) !default;
33
33
  $link-color-visited: rgb(20, 77, 250) !default;
34
34
  $link-color-hover: rgb(255, 77, 20) !default;
35
+
36
+ :root {
37
+ --font-size-large: #{$font-size-large};
38
+ --font-size-increased: #{$font-size-increased};
39
+ --font-size-normal: #{$font-size-normal};
40
+ --font-size-decreased: #{$font-size-decreased};
41
+ --font-size-small: #{$font-size-small};
42
+ }
@@ -1,22 +1,27 @@
1
1
  class AboutController < ApplicationController
2
2
  # get /about
3
3
  def index
4
- @editable_page = EditablePage.find_localized('about', locale)
4
+ @editable_page = EditablePage.localized_page('about', locale)
5
5
 
6
6
  render :editable
7
7
  end
8
8
 
9
9
  # get /tos
10
10
  def tos
11
- @editable_page = EditablePage.find_localized('tos', locale)
11
+ @editable_page = EditablePage.localized_page('tos', locale)
12
12
 
13
13
  render :editable
14
14
  end
15
15
 
16
16
  # get /privacy
17
17
  def privacy
18
- @editable_page = EditablePage.find_localized('privacy', locale)
18
+ @editable_page = EditablePage.localized_page('privacy', locale)
19
19
 
20
20
  render :editable
21
21
  end
22
+
23
+ # get /contact
24
+ def contact
25
+ @editable_page = EditablePage.localized_page('contact', locale)
26
+ end
22
27
  end
@@ -1,9 +1,11 @@
1
1
  class Admin::EditablePagesController < AdminController
2
+ include EntityPriority
3
+
2
4
  before_action :set_entity, except: [:index]
3
5
 
4
6
  # get /admin/editable_pages
5
7
  def index
6
- @collection = EditablePage.page_for_administration
8
+ @collection = EditablePage.list_for_administration
7
9
  end
8
10
 
9
11
  # get /admin/editable_pages/:id
@@ -8,7 +8,7 @@ class EditablePagesController < AdminController
8
8
 
9
9
  # post /editable_pages
10
10
  def create
11
- @entity = EditablePage.new(creation_parameters)
11
+ @entity = EditablePage.new(entity_parameters)
12
12
  if @entity.save
13
13
  form_processed_ok(admin_editable_page_path(id: @entity.id))
14
14
  else
@@ -54,8 +54,4 @@ class EditablePagesController < AdminController
54
54
  def entity_parameters
55
55
  params.require(:editable_page).permit(EditablePage.entity_parameters)
56
56
  end
57
-
58
- def creation_parameters
59
- params.require(:editable_page).permit(EditablePage.creation_parameters)
60
- end
61
57
  end
@@ -0,0 +1,11 @@
1
+ class FallbackController < ApplicationController
2
+ # get (:editable_page_url)
3
+ def show
4
+ url = params[:editable_page_url]
5
+
6
+ @editable_page = EditablePage.fallback_page("/#{url}", locale)
7
+ if @editable_page.nil?
8
+ handle_http_404("Cannot find fallback page for url /#{url}")
9
+ end
10
+ end
11
+ end
@@ -62,7 +62,15 @@ class MediaFilesController < ApplicationController
62
62
 
63
63
  @entity = MediaFile.create!(parameters)
64
64
 
65
- render layout: false
65
+ if params[:CKEditorFuncNum]
66
+ render layout: false
67
+ else
68
+ render json: {
69
+ uploaded: 1,
70
+ fileName: File.basename(@entity.name),
71
+ url: @entity.file.medium.url
72
+ }
73
+ end
66
74
  end
67
75
 
68
76
  protected
@@ -2,10 +2,15 @@ class My::ProfilesController < ApplicationController
2
2
  include Authentication
3
3
 
4
4
  before_action :redirect_authorized_user, only: [:new, :create]
5
- before_action :restrict_anonymous_access, except: [:new, :create]
5
+ before_action :restrict_anonymous_access, except: [:check, :new, :create]
6
6
 
7
7
  layout 'profile', only: [:show, :edit]
8
8
 
9
+ # post /my/profile/check
10
+ def check
11
+ @entity = User.new(creation_parameters)
12
+ end
13
+
9
14
  # get /my/profile/new
10
15
  def new
11
16
  @entity = User.new
@@ -0,0 +1,20 @@
1
+ # Adds method for validating model in controllers
2
+ #
3
+ # @author Maxim Khan-Magomedov <maxim.km@gmail.com>
4
+ module Checkable
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ # @param [Integer] id
9
+ # @param [Hash] parameters
10
+ def self.instance_for_check(id, parameters)
11
+ if id.blank?
12
+ entity = new(parameters)
13
+ else
14
+ entity = find_by(id: id)
15
+ entity.assign_attributes(parameters)
16
+ end
17
+ entity
18
+ end
19
+ end
20
+ end
@@ -12,6 +12,7 @@ class EditablePage < ApplicationRecord
12
12
 
13
13
  belongs_to :language, optional: true
14
14
 
15
+ after_initialize :set_next_priority
15
16
  before_validation { self.slug = slug.strip unless slug.nil? }
16
17
  before_validation :normalize_priority
17
18
 
@@ -19,54 +20,70 @@ class EditablePage < ApplicationRecord
19
20
  validates_length_of :name, maximum: NAME_LIMIT
20
21
  validates_length_of :slug, maximum: SLUG_LIMIT
21
22
  validates_length_of :title, maximum: META_LIMIT
23
+ validates_length_of :image_alt_text, maximum: META_LIMIT
22
24
  validates_length_of :keywords, maximum: META_LIMIT
23
25
  validates_length_of :description, maximum: META_LIMIT
24
26
  validates_length_of :body, maximum: BODY_LIMIT
25
27
  validates_uniqueness_of :slug, scope: [:language_id]
26
28
 
29
+ scope :ordered_by_priority, -> { order('priority asc, slug asc') }
27
30
  scope :ordered_by_slug, -> { order('slug asc') }
28
31
  scope :with_slug_like, ->(slug) { where('slug ilike ?', "%#{slug}%") unless slug.blank? }
29
32
  scope :with_slug, ->(slug) { where('lower(slug) = lower(?)', slug) unless slug.blank? }
30
33
  scope :siblings, ->(s) { where(language: s.language, nav_group: s.nav_group) }
34
+ scope :list_for_administration, -> { ordered_by_priority }
31
35
 
32
36
  def self.page_for_administration
33
37
  ordered_by_slug
34
38
  end
35
39
 
36
40
  def self.entity_parameters
37
- %i(image name title keywords description body language_id)
41
+ %i(body description image image_alt_text keywords language_id name nav_group title slug url)
38
42
  end
39
43
 
40
- def self.creation_parameters
41
- entity_parameters + %i(slug)
44
+ # @param [String] slug
45
+ # @param [String] language_code
46
+ # @deprecated use #localized_page
47
+ def self.find_localized(slug, language_code)
48
+ localized_page(slug, language_code)
42
49
  end
43
50
 
44
51
  # @param [String] slug
45
52
  # @param [String] language_code
46
- def self.find_localized(slug, language_code = nil)
53
+ def self.localized_page(slug, language_code)
54
+ language = Language.find_by(code: language_code)
55
+ find_by(slug: slug, language: language) || find_by(slug: slug)
56
+ end
57
+
58
+ # @param [String] url
59
+ # @param [String] language_code
60
+ def self.fallback_page(url, language_code)
47
61
  language = Language.find_by(code: language_code)
48
- criteria = { slug: slug }
49
- instance = find_by(criteria.merge(language: language))
50
- instance || find_by(criteria)
62
+ find_by(url: url, language: language) || find_by(url: url)
63
+ end
64
+
65
+ # @param [User] user
66
+ def editable_by?(user)
67
+ UserPrivilege.user_has_privilege?(user, :chief_editor)
51
68
  end
52
69
 
53
70
  # @param [Integer] delta
54
71
  def change_priority(delta)
55
72
  new_priority = priority + delta
56
- adjacent = self.class.siblings(self).find_by(priority: new_priority)
73
+ adjacent = self.class.find_by(priority: new_priority)
57
74
  if adjacent.is_a?(self.class) && (adjacent.id != id)
58
75
  adjacent.update!(priority: priority)
59
76
  end
60
77
  update(priority: new_priority)
61
78
 
62
- self.class.siblings(self).map { |e| [e.id, e.priority] }.to_h
79
+ self.class.ordered_by_priority.map { |e| [e.id, e.priority] }.to_h
63
80
  end
64
81
 
65
82
  private
66
83
 
67
84
  def set_next_priority
68
85
  if id.nil? && priority == 1
69
- self.priority = self.class.siblings(self).maximum(:priority).to_i + 1
86
+ self.priority = self.class.maximum(:priority).to_i + 1
70
87
  end
71
88
  end
72
89
 
@@ -5,13 +5,13 @@ class FeedbackRequest < ApplicationRecord
5
5
  EMAIL_LIMIT = 250
6
6
  PHONE_LIMIT = 30
7
7
  COMMENT_LIMIT = 5000
8
- PER_PAGE = 20
9
8
 
10
9
  toggleable :processed
11
10
 
12
11
  belongs_to :language, optional: true
13
12
  belongs_to :agent, optional: true
14
13
 
14
+ validates_acceptance_of :consent
15
15
  validates_length_of :name, maximum: NAME_LIMIT
16
16
  validates_length_of :phone, maximum: PHONE_LIMIT
17
17
  validates_length_of :comment, maximum: COMMENT_LIMIT
@@ -20,13 +20,14 @@ class FeedbackRequest < ApplicationRecord
20
20
 
21
21
  scope :recent, -> { order('id desc') }
22
22
  scope :unprocessed, -> { where(processed: false) }
23
+ scope :list_for_administration, -> { recent }
23
24
 
24
25
  # @param [Integer] page
25
26
  def self.page_for_administration(page = 1)
26
- recent.page(page).per(PER_PAGE)
27
+ list_for_administration.page(page)
27
28
  end
28
29
 
29
30
  def self.creation_parameters
30
- %i(name email phone comment)
31
+ %i(comment consent email name phone)
31
32
  end
32
33
  end