cas-cms 0.1.3 → 1.0.0.alpha1

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 (45) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +28 -18
  3. data/app/assets/config/cas_manifest.js +2 -0
  4. data/app/assets/javascripts/cas/application.js +4 -2
  5. data/app/assets/javascripts/cas/fileupload_manifest.js +2 -2
  6. data/app/assets/stylesheets/cas/application.sass +4 -4
  7. data/app/assets/stylesheets/cas/form.sass +2 -0
  8. data/app/assets/stylesheets/cas/layout.sass +2 -0
  9. data/app/assets/stylesheets/cas/tables.sass +3 -0
  10. data/app/assets/stylesheets/cas/typography.sass +2 -0
  11. data/app/assets/stylesheets/cas/vendors/{selectize.default.css → selectize.css} +0 -0
  12. data/app/controllers/cas/activities_controller.rb +9 -0
  13. data/app/controllers/cas/application_controller.rb +13 -0
  14. data/app/controllers/cas/file_uploads_controller.rb +1 -1
  15. data/app/controllers/cas/sites/application_controller.rb +0 -13
  16. data/app/controllers/cas/sites/sections/contents_controller.rb +10 -1
  17. data/app/controllers/cas/sites/users_controller.rb +1 -1
  18. data/app/models/cas/activity.rb +30 -0
  19. data/app/models/cas/content.rb +14 -5
  20. data/app/models/cas/media_file.rb +1 -1
  21. data/app/models/cas/sites_user.rb +1 -1
  22. data/app/models/cas/user.rb +3 -2
  23. data/app/uploaders/file_uploader.rb +1 -1
  24. data/app/views/cas/activities/index.html.erb +56 -0
  25. data/app/views/cas/sites/sections/contents/index.html.erb +0 -1
  26. data/app/views/layouts/cas/application.html.erb +3 -2
  27. data/config/initializers/acts_as_taggable.rb +1 -1
  28. data/config/initializers/shrine.rb +19 -15
  29. data/config/routes.rb +5 -1
  30. data/db/migrate/20180114124600_create_cas_activities.rb +16 -0
  31. data/db/migrate/20230220165900_add_subject_title_to_activities.rb +6 -0
  32. data/lib/cas/config.rb +8 -3
  33. data/lib/cas/engine.rb +5 -1
  34. data/lib/cas/exceptions.rb +7 -0
  35. data/lib/cas/form_field.rb +6 -2
  36. data/lib/cas/installation.rb +103 -0
  37. data/lib/cas/section_config.rb +25 -31
  38. data/lib/cas/version.rb +1 -1
  39. data/lib/cas.rb +3 -1
  40. data/lib/generators/cas/USAGE +14 -0
  41. data/lib/generators/cas/install_generator.rb +14 -0
  42. data/lib/generators/cas/templates/cas.config.yml +82 -0
  43. data/lib/tasks/cas_tasks.rake +6 -4
  44. metadata +51 -15
  45. data/lib/cas/setup.rb +0 -60
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: e4cf4081ecbfe1307e6d39d6b64156b98a494f3b
4
- data.tar.gz: b1b59204366430b4ff05abf74dd64107524373d5
2
+ SHA256:
3
+ metadata.gz: 8f12f0fb6a3b7c3c29caf99a139194aac107be867f347f5738d2b9cc215a5581
4
+ data.tar.gz: 950fd904a33eb23cd9467cc2324a6bea612a1e920a4c90d227ace4d299276257
5
5
  SHA512:
6
- metadata.gz: 4144df8905ec86fd3102dcf0cfc7cef2053b314f40a749059a305e97b552187144fc8f669e13e90de69649092522a6edf3c9fc8f40bc23f9637be297d8d436da
7
- data.tar.gz: d66d1a0ea481f0e9562e0f370a8dda0fbadcd23787fcbe260a9bfeb9ee3c3e9a8314ae7553312b2854258ffe17343037c24f89a31b5c579a7fe72836217e3336
6
+ metadata.gz: b7f891b42b447860a676e36aa868221a0165d81819f95e3d3ea3f9b88111eeb21eaa3788468156e9818e0d7c119b285faba5538cb47a8b27f76fea776505c7be
7
+ data.tar.gz: 8c720e1eb5382606cdf7679d242617734efcfb40501c5a813da22fcafe9a0d958c7c4be431805c9d8f262e0dd16725ce106cef2398b290d8c5040cd77ecb3445
data/README.md CHANGED
@@ -1,34 +1,32 @@
1
1
  # Cas
2
- Short description and motivation.
3
2
 
4
3
  ## Usage
5
4
 
6
- How to use my plugin.
7
-
8
- ## Installation
9
-
10
5
  Add this line to your application's Gemfile:
11
6
 
12
7
  ```ruby
13
8
  gem 'cas'
14
9
  ```
15
10
 
16
- ### Setup
11
+ ### Installation
12
+
13
+ ```
14
+ bin/rails generate cas:install
15
+ ```
17
16
 
18
- **Engine:** Cas is mounted in your main Rails application. Say your application
19
- is called MyBlog, you make can make it accessible at `myblog.com/admin`
20
- by setting the following in the `config/routes.rb` file in your main
21
- application:
17
+ This adds an `/admin` entry to `config/routes.rb` and generates a new file,
18
+ `config/cas.config.yml` which contains all sections your site is supposed to
19
+ have.
22
20
 
23
- ```ruby
24
- Rails.application.routes.draw do
25
- mount Cas::Engine, at: "/admin"
21
+ Once the file is edited, run
26
22
 
27
- # ... other routes
28
- end
29
23
  ```
24
+ bin/rails cas:apply_config
25
+ ```
26
+
27
+ ### File Uploads
30
28
 
31
- **S3:** you need S3 credentials to use Cas (for file uploads). Set the
29
+ You need S3 credentials to use Cas (for file uploads). Set the
32
30
  following ENV vars (e.g paste in your `~/.bash_profile` or use the `dotenv`
33
31
  gem in your main Rails application):
34
32
 
@@ -37,8 +35,20 @@ gem in your main Rails application):
37
35
  export S3_REGION="value"
38
36
  export S3_BUCKET="value"
39
37
 
40
- ## Contributing
41
- Contribution directions go here.
38
+ ## Development
39
+
40
+ Quick start:
41
+
42
+ ```
43
+ bundle install
44
+ bundle exec rake db:create db:migrate db:test:prepare
45
+ cd spec/test_app/ && bin/rails server
46
+ ```
47
+
48
+ ### The Longer Version
49
+
50
+
42
51
 
43
52
  ## License
53
+
44
54
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -1,2 +1,4 @@
1
+ //= link cas/application.js
2
+ //= link cas/application.css
1
3
  //= link_directory ../javascripts/cas .js
2
4
  //= link_directory ../stylesheets/cas .css
@@ -1,6 +1,6 @@
1
1
  //= require jquery
2
2
  //= require jquery_ujs
3
- //= require tinymce-jquery
3
+ //= require tinymce
4
4
  //= require cas/vendor/selectize.min
5
5
  //= require_self
6
6
 
@@ -37,6 +37,8 @@ $(document).ready(function() {
37
37
  });
38
38
 
39
39
  tinyMCE.init({
40
+ branding: false,
41
+ promotion: false,
40
42
  selector: 'textarea.editor',
41
43
  mode : "exact",
42
44
  relative_urls : false,
@@ -48,7 +50,7 @@ $(document).ready(function() {
48
50
  inline_styles: false,
49
51
  extended_valid_elements: "embed,param,object,iframe[src|title|width|height|allowfullscreen|frameborder]",
50
52
  language : "pt_BR",
51
- plugins : 'image,imagetools,code,paste,pagebreak,table,wordcount,link',
53
+ plugins : 'image code pagebreak table wordcount link',
52
54
  default_link_target: "_blank",
53
55
  images_upload_url: paths.fileUpload.path,
54
56
  images_upload_credentials: true
@@ -30,7 +30,7 @@ var UploadSharedFunctions = {
30
30
  console.log("error", e);
31
31
  console.log("data", data);
32
32
  data.progressBar.remove();
33
- alert('Falha ao enviar arquivo: '+data.files[0].name);
33
+ alert('Failed sending file: '+data.files[0].name);
34
34
  }
35
35
  };
36
36
 
@@ -47,7 +47,7 @@ var ImageGalleryUploadFunctions = {
47
47
  for (var index in data.originalFiles) {
48
48
  var file = data.originalFiles[index];
49
49
  if(file['type'].length && !acceptFileTypes.test(file['type'])) {
50
- alert('O arquivo enviado não é uma imagem.');
50
+ alert('File is not a valid image.');
51
51
  return false;
52
52
  }
53
53
  }
@@ -1,10 +1,10 @@
1
-
2
1
  /*
3
- * require_tree .
4
2
  *= require_self
3
+ * require cas/vendors/simplegrid.css
4
+ * require ./cas/vendors/selectize.default.css
5
5
  */
6
- @import 'vendors/simplegrid.css'
7
- @import 'vendors/selectize.default.css'
6
+ @import 'cas/vendors/selectize.css'
7
+ @import 'cas/vendors/simplegrid.css'
8
8
 
9
9
  @import 'mixins'
10
10
  @import 'colors'
@@ -1,3 +1,5 @@
1
+ @import 'colors'
2
+
1
3
  label
2
4
  display: block
3
5
  div.input.boolean
@@ -1,3 +1,5 @@
1
+ @import 'colors'
2
+ @import 'mixins'
1
3
 
2
4
  body
3
5
  margin: 0
@@ -1,3 +1,6 @@
1
+ @import 'colors'
2
+ @import 'mixins'
3
+
1
4
  table
2
5
  width: 100%
3
6
  border-spacing: 0
@@ -1,4 +1,6 @@
1
1
  // @import url('https://fonts.googleapis.com/css?family=Lato')
2
+ @import 'colors'
3
+ @import 'mixins'
2
4
 
3
5
  body
4
6
  margin: 0
@@ -0,0 +1,9 @@
1
+ class Cas::ActivitiesController < Cas::ApplicationController
2
+ def index
3
+ @activities = Cas::Activity
4
+ .where(site_id: current_user.sites.map(&:id))
5
+ .order('created_at DESC')
6
+ .page(params[:page])
7
+ .per(25)
8
+ end
9
+ end
@@ -5,6 +5,7 @@ module Cas
5
5
  before_action :set_current_user
6
6
  before_action :set_user_sites
7
7
  before_action :set_domain
8
+ before_action :set_site
8
9
 
9
10
  private
10
11
 
@@ -22,6 +23,18 @@ module Cas
22
23
  if @domain.blank? || (ENV["DOMAIN"].blank? && @domain == "localhost")
23
24
  @domain = ::Cas::Site.first!.domains.first
24
25
  end
26
+ rescue ActiveRecord::RecordNotFound => e
27
+ raise Cas::Exceptions::IncompleteSetup, "IncompleteSetup: check README.md. #{e.message}: #{e.inspect}"
28
+ end
29
+
30
+ def set_site
31
+ if params[:site_id].present?
32
+ @site = ::Cas::Site.find_by!(slug: params[:site_id])
33
+ else
34
+ @site = ::Cas::Site
35
+ .where("cas_sites.domains::text[] && '{#{@domain}}'::text[]")
36
+ .first!
37
+ end
25
38
  end
26
39
  end
27
40
  end
@@ -1,6 +1,6 @@
1
1
  class Cas::FileUploadsController < Cas::ApplicationController
2
2
  skip_before_action :authenticate_user!
3
- skip_before_filter :verify_authenticity_token
3
+ skip_before_action :verify_authenticity_token
4
4
 
5
5
  def create
6
6
  file = params.fetch(:file)
@@ -1,15 +1,2 @@
1
1
  class Cas::Sites::ApplicationController < ::Cas::ApplicationController
2
- before_action :set_site
3
-
4
- private
5
-
6
- def set_site
7
- if params[:site_id].present?
8
- @site = ::Cas::Site.find_by!(slug: params[:site_id])
9
- else
10
- @site = ::Cas::Site
11
- .where("cas_sites.domains::text[] && '{#{@domain}}'::text[]")
12
- .first!
13
- end
14
- end
15
2
  end
@@ -25,10 +25,12 @@ module Cas
25
25
  @content.section_id = @section.id
26
26
  @content.tag_list = content_params[:tag_list] if content_params[:tag_list]
27
27
  success = @content.save!
28
+ ::Cas::Activity.create!(user: current_user, site: @site, subject: @content, event_name: 'create')
28
29
  associate_files(@content, :images)
29
30
  associate_files(@content, :attachments)
30
31
  end
31
32
  rescue ActiveRecord::RecordInvalid
33
+ Rails.logger.info "Errors: #{@content.errors.full_messages.inspect}"
32
34
  success = nil
33
35
  end
34
36
 
@@ -62,6 +64,7 @@ module Cas
62
64
  success = @content.update!(content_params)
63
65
  associate_files(@content, :images)
64
66
  associate_files(@content, :attachments)
67
+ ::Cas::Activity.create!(user: current_user, site: @site, subject: @content, event_name: 'update')
65
68
  end
66
69
  rescue ActiveRecord::RecordInvalid
67
70
  success = nil
@@ -90,6 +93,11 @@ module Cas
90
93
 
91
94
  def content_params
92
95
  @content_params ||= begin
96
+ # When no file is uploaded, when the content form is submitted the
97
+ # `file` input ends up being sent empty (e.g file: [""]). This confuses
98
+ # Rails.
99
+ params[:content].delete(:file) if params[:content][:file].map(&:presence).compact.blank?
100
+
93
101
  result = params.require(:content).permit(
94
102
  :category_id,
95
103
  :title,
@@ -100,7 +108,8 @@ module Cas
100
108
  :text,
101
109
  :url,
102
110
  :embedded,
103
- :tag_list
111
+ :tag_list,
112
+ :file
104
113
  )
105
114
 
106
115
  unless result.keys.map(&:to_sym).include?(:published)
@@ -36,7 +36,7 @@ module Cas
36
36
  without_password = user_params.except(:password, :password_confirmation)
37
37
  success = @user.update_without_password(without_password)
38
38
  else
39
- success = @user.update_attributes(user_params)
39
+ success = @user.update(user_params)
40
40
  end
41
41
 
42
42
  if success
@@ -0,0 +1,30 @@
1
+ module Cas
2
+ class Activity < ApplicationRecord
3
+ belongs_to :site
4
+ belongs_to :user, optional: true
5
+ belongs_to :subject, polymorphic: true
6
+
7
+ # To prevent losing data in case the subject is ever destroyed
8
+ before_validation :cache_description
9
+
10
+ private
11
+
12
+ def cache_description
13
+ if self.user_description.blank?
14
+ user_string = [user.name]
15
+ user_string << ["(admin)"] if user.admin?
16
+ self.user_description = user_string.join(" ")
17
+ end
18
+
19
+ if self.subject_description.blank?
20
+ subject_string = []
21
+ if subject.respond_to?(:title)
22
+ subject_string << [subject.title]
23
+ elsif subject.respond_to?(:name)
24
+ subject_string << [subject.name]
25
+ end
26
+ self.subject_description = subject_string.join(" ")
27
+ end
28
+ end
29
+ end
30
+ end
@@ -9,12 +9,21 @@ module Cas
9
9
  serialize :metadata
10
10
 
11
11
  belongs_to :section
12
+ belongs_to :category, optional: true
13
+ belongs_to :author, class_name: "::Cas::User"
14
+
15
+ has_many :images,
16
+ ->{ where(media_type: :image).order("cas_media_files.order ASC") },
17
+ class_name: "::Cas::MediaFile", as: :attachable, dependent: :destroy
18
+ has_many :attachments,
19
+ ->{ where(media_type: :attachment).order("cas_media_files.order ASC") },
20
+ class_name: "::Cas::MediaFile", as: :attachable, dependent: :destroy
21
+ has_many :activities, as: :subject
22
+
12
23
  has_one :site, through: :section
13
- belongs_to :category
14
- belongs_to :author, class_name: Cas::User
15
- has_many :images, ->{ where(media_type: :image).order("cas_media_files.order ASC") }, class_name: Cas::MediaFile, as: :attachable, dependent: :destroy
16
- has_many :attachments, ->{ where(media_type: :attachment).order("cas_media_files.order ASC") }, class_name: Cas::MediaFile, as: :attachable, dependent: :destroy
17
- has_one :cover_image, ->{ where(media_type: :image, cover: true) }, class_name: Cas::MediaFile, as: :attachable
24
+ has_one :cover_image,
25
+ ->{ where(media_type: :image, cover: true) },
26
+ class_name: "::Cas::MediaFile", as: :attachable
18
27
 
19
28
  validates :title, presence: true
20
29
 
@@ -6,7 +6,7 @@ module Cas
6
6
  class UnknownFileService < StandardError; end
7
7
 
8
8
  belongs_to :attachable, polymorphic: true
9
- belongs_to :author, class_name: "Cas::User"
9
+ belongs_to :author, class_name: "::Cas::User"
10
10
 
11
11
  before_validation :set_media_type
12
12
  before_save :set_image_as_unique_cover
@@ -2,6 +2,6 @@ module Cas
2
2
  class SitesUser < ApplicationRecord
3
3
  belongs_to :site
4
4
  belongs_to :user
5
- belongs_to :owner, class_name: '::Cas::User'
5
+ belongs_to :owner, class_name: '::Cas::User', optional: true
6
6
  end
7
7
  end
@@ -6,9 +6,10 @@ module Cas
6
6
  :rememberable, :trackable, :validatable, request_keys: [:domain]
7
7
 
8
8
  has_many :contents
9
- has_many :files, class_name: 'Cas::MediaFile', as: :attachable
10
- has_many :sites_users, class_name: 'Cas::SitesUser'
9
+ has_many :files, class_name: '::Cas::MediaFile', as: :attachable
10
+ has_many :sites_users, class_name: '::Cas::SitesUser'
11
11
  has_many :sites, through: :sites_users
12
+ has_many :activities, as: :subject
12
13
 
13
14
  validates :name, presence: true, length: { maximum: 50 }
14
15
  validates :email, presence: true, length: { maximum: 255 },
@@ -9,11 +9,11 @@ class ::FileUploader < Shrine
9
9
  end
10
10
  original = (io.respond_to?(:[]) && io[:original]) ? io[:original] : io
11
11
  result = result.merge(original: original) unless result.keys.include?(:original)
12
+ Rails.logger.info "FileUploader, versions: [#{result.keys.join(", ")}]"
12
13
  result
13
14
  end
14
15
 
15
16
  def generate_location(io, context)
16
- Rails.logger.info "FileUploader#generate_location"
17
17
  year = Time.now.strftime("%Y")
18
18
  month = Time.now.strftime("%m")
19
19
  original_filename = context[:metadata]["filename"]
@@ -0,0 +1,56 @@
1
+ <div class="grid">
2
+ <div class="col-1-1">
3
+ <h1>Atividades</h1>
4
+ </div>
5
+ </div>
6
+
7
+ <br />
8
+
9
+ <table>
10
+ <thead>
11
+ <tr>
12
+ <th>
13
+ </th>
14
+ <th>
15
+ </th>
16
+ <th>Data</th>
17
+ </tr>
18
+ </thead>
19
+
20
+ <tbody>
21
+ <% @activities.each do |activity| %>
22
+ <tr>
23
+ <td>
24
+ <%= activity.site.name %>
25
+ </td>
26
+ <td>
27
+ <% if activity.user.present? %>
28
+ <strong><%= activity.user.name %></strong>
29
+ <% else %>
30
+ <strong><%= activity.user_description %></strong>
31
+ <% end %>
32
+ <% if activity.event_name == 'create' %>
33
+ criou
34
+ <% elsif activity.event_name == 'update'%>
35
+ editou
36
+ <% end %>
37
+ <% if activity.subject.present? %>
38
+ <strong>
39
+ <%= link_to activity.subject.title,
40
+ edit_site_section_content_path(@site, activity.subject.section, activity.subject)
41
+ %>
42
+ </strong>
43
+ <% else %>
44
+ <%= activity.subject_description %>
45
+ <% end %>
46
+ </td>
47
+ <td>
48
+ <%= l(activity.created_at, format: :short) %>
49
+ </td>
50
+ </tr>
51
+ <% end %>
52
+ </tbody>
53
+ </table>
54
+ <br>
55
+
56
+ <%= paginate @activities %>
@@ -12,7 +12,6 @@
12
12
  <%= link_to 'Novo conteúdo',
13
13
  new_site_section_content_path(@site, @section),
14
14
  id: 'new-content' %>
15
-
16
15
  <br />
17
16
  <br />
18
17
 
@@ -26,7 +26,7 @@
26
26
 
27
27
  <%= csrf_meta_tags %>
28
28
  </head>
29
- <body class="<%= "site-#{@site.id}" if @current_user.present? %>">
29
+ <body class="<%= "site-#{@site.id}" if @current_user.present? && @site.present? %>">
30
30
 
31
31
  <header>
32
32
  <div class="grid top">
@@ -43,7 +43,7 @@
43
43
  <% else %>
44
44
  <select id="select-site">
45
45
  <% @user_sites.each do |site| %>
46
- <% selected = site.id == @site.id %>
46
+ <% selected = site.id == @site&.id %>
47
47
  <option
48
48
  value="<%= site_sections_path(site) %>"
49
49
  <%= 'selected="selected"' if selected %>
@@ -70,6 +70,7 @@
70
70
  <ul>
71
71
  <% if user_signed_in? %>
72
72
  <li><%= link_to "Conteúdo", cas.site_sections_path(@site) %></li>
73
+ <li><%= link_to "Atividades", cas.activities_path, id: "go-to-activities" %></li>
73
74
  <% end %>
74
75
  <% if user_signed_in? && current_user.admin? %>
75
76
  <li><%= link_to "Pessoas", cas.site_users_path(@site), id: "list-people" %></li>
@@ -1 +1 @@
1
- ActsAsTaggableOn.delimiter = [',', ' ']
1
+ ActsAsTaggableOn.delimiter = [',']
@@ -1,3 +1,6 @@
1
+ # On why we use Shrine over Active Storage:
2
+ # https://github.com/shrinerb/shrine/blob/d9aba64bd5515584645f8885c76d56fa1a842bac/doc/advantages.md
3
+
1
4
  require 'shrine'
2
5
 
3
6
  Shrine.plugin :activerecord
@@ -19,24 +22,25 @@ if Rails.env.test?
19
22
  }
20
23
  else
21
24
  if ENV["S3_ACCESS_KEY_ID"].blank?
22
- msg = "You need to configure S3 credentials. See the README.md for more details."
23
- puts msg
25
+ msg = "You need to configure S3 credentials. See the README.md for more details. File uploads will be broken until you fix it."
24
26
  Rails.logger.error msg
25
- end
27
+ puts msg
26
28
 
27
- s3_options = {
28
- access_key_id: ENV.fetch("S3_ACCESS_KEY_ID"),
29
- secret_access_key: ENV.fetch("S3_SECRET_ACCESS_KEY"),
30
- region: ENV.fetch("S3_REGION"),
31
- bucket: ENV.fetch("S3_BUCKET"),
32
- }
29
+ else
30
+ s3_options = {
31
+ access_key_id: ENV.fetch("S3_ACCESS_KEY_ID"),
32
+ secret_access_key: ENV.fetch("S3_SECRET_ACCESS_KEY"),
33
+ region: ENV.fetch("S3_REGION"),
34
+ bucket: ENV.fetch("S3_BUCKET"),
35
+ }
33
36
 
34
- require "shrine/storage/s3"
35
- config = Cas::Config.new.uploads
36
- Shrine.storages = {
37
- cache: Shrine::Storage::S3.new(prefix: config[:cache_directory_prefix], **s3_options),
38
- store: Shrine::Storage::S3.new(prefix: config[:store_directory_prefix], **s3_options),
39
- }
37
+ require "shrine/storage/s3"
38
+ config = Cas::Config.new.uploads
39
+ Shrine.storages = {
40
+ cache: Shrine::Storage::S3.new(prefix: config[:cache_directory_prefix], **s3_options),
41
+ store: Shrine::Storage::S3.new(prefix: config[:store_directory_prefix], **s3_options),
42
+ }
43
+ end
40
44
  end
41
45
 
42
46
  Shrine::Attacher.promote do |data|
data/config/routes.rb CHANGED
@@ -1,8 +1,11 @@
1
1
  require 'sidekiq/web'
2
- Sidekiq::Web.set :session_secret, Rails.application.secrets[:secret_key_base]
2
+ # TODO - need to migrate Sidekiq
3
+ #Sidekiq::Web.set :session_secret, Rails.application.secrets[:secret_key_base]
3
4
 
4
5
  Cas::Engine.routes.draw do
5
6
  mount Shrine.presign_endpoint(:cache) => "/files/cache/presign"
7
+ # TODO - fix
8
+ # mount Shrine.upload_endpoint(:cache) => "/files/upload"
6
9
 
7
10
  authenticate :user, ->(u){ u.roles.include?('admin') } do
8
11
  mount Sidekiq::Web => '/sidekiq'
@@ -14,6 +17,7 @@ Cas::Engine.routes.draw do
14
17
  controllers: { sessions: "cas/devise/sessions" },
15
18
  skip: :registrations
16
19
 
20
+ resources :activities, only: [:index]
17
21
  resources :sites, only: [:index] do
18
22
  resources :users, controller: 'sites/users'
19
23
 
@@ -0,0 +1,16 @@
1
+ class CreateCasActivities < ActiveRecord::Migration[5.0]
2
+ def change
3
+ create_table :cas_activities, id: :uuid do |t|
4
+ t.uuid :site_id
5
+ t.uuid :user_id
6
+ t.string :event_name
7
+ t.uuid :subject_id
8
+ t.string :subject_type
9
+
10
+ t.timestamps
11
+ end
12
+ add_index :cas_activities, :site_id
13
+ add_index :cas_activities, :user_id
14
+ add_index :cas_activities, [:subject_id, :subject_type]
15
+ end
16
+ end
@@ -0,0 +1,6 @@
1
+ class AddSubjectTitleToActivities < ActiveRecord::Migration[5.0]
2
+ def change
3
+ add_column :cas_activities, :user_description, :string
4
+ add_column :cas_activities, :subject_description, :string
5
+ end
6
+ end
data/lib/cas/config.rb CHANGED
@@ -10,6 +10,7 @@ module Cas
10
10
  def uploads
11
11
  uploads = config["uploads"] || {}
12
12
 
13
+ # TODO - clarify what this is and how to configure
13
14
  {
14
15
  cache_directory_prefix: uploads["cache_directory_prefix"] || "cache",
15
16
  store_directory_prefix: uploads["store_directory_prefix"] || "store"
@@ -19,13 +20,17 @@ module Cas
19
20
  private
20
21
 
21
22
  def read_file
22
- @file ||= YAML.load_file(filename)
23
+ begin
24
+ @file ||= YAML.safe_load_file(filename, aliases: true)
25
+ rescue NoMethodError, ArgumentError
26
+ @file ||= YAML.load_file(filename)
27
+ end
23
28
  end
24
29
 
25
30
  def filename
26
31
  @filename ||= begin
27
- if File.exists?("cas.yml")
28
- "cas.yml"
32
+ if File.exists?(Cas::CONFIG_PATH)
33
+ Cas::CONFIG_PATH
29
34
  elsif ENV['RAILS_ENV'] == 'test'
30
35
  "spec/fixtures/cas.yml"
31
36
  else
data/lib/cas/engine.rb CHANGED
@@ -16,7 +16,11 @@ module Cas
16
16
  end
17
17
  end
18
18
 
19
- config.assets.precompile += ["cas/fileupload_manifest.js"]
19
+ config.assets.precompile += [
20
+ "cas/application.css",
21
+ "cas/application.js",
22
+ "cas/fileupload_manifest.js"
23
+ ]
20
24
 
21
25
  config.active_record.primary_key = :uuid
22
26
  config.generators do |g|
@@ -0,0 +1,7 @@
1
+ module Cas
2
+ module Exceptions
3
+ class Error < StandardError; end
4
+ class IncompleteSetup < Error; end
5
+ class UndefinedSite < Cas::Exceptions::Error; end
6
+ end
7
+ end
@@ -15,13 +15,17 @@ module Cas
15
15
  if Rails.env.test?
16
16
  "spec/fixtures/cas.yml"
17
17
  else
18
- "cas.yml"
18
+ Cas::CONFIG_PATH
19
19
  end
20
20
  end
21
21
 
22
22
  def load_field
23
23
  @config ||= begin
24
- config_file = YAML.load_file(filename)
24
+ begin
25
+ config_file = YAML.safe_load_file(filename, aliases: true)
26
+ rescue NoMethodError, ArgumentError
27
+ config_file = YAML.load_file(filename)
28
+ end
25
29
  sites = config_file["sites"]
26
30
  site = sites[@section.site.slug]
27
31
  section = site["sections"]
@@ -0,0 +1,103 @@
1
+ module Cas
2
+ class Installation
3
+ def initialize(filename: nil, logger: Rails.logger)
4
+ @logger = logger
5
+ @filename = filename
6
+ @filename ||= begin
7
+ if Rails.env.test?
8
+ "spec/fixtures/cas.yml"
9
+ else
10
+ Cas::CONFIG_PATH
11
+ end
12
+ end
13
+
14
+ # Ruby 3.0 comes with Psych 3, while Ruby 3.1 comes with Psych 4, which
15
+ # has a major breaking change (diff 3.3.2 → 4.0.0).
16
+ #
17
+ # The new YAML loading methods (Psych 4) do not load aliases unless
18
+ # they get the aliases: true argument. The old YAML loading methods
19
+ # (Psych 3) do not support the :aliases keyword.
20
+ begin
21
+ @config = YAML.safe_load_file(@filename, aliases: true)
22
+ rescue NoMethodError, ArgumentError
23
+ @config = YAML.load_file(@filename)
24
+ end
25
+ end
26
+
27
+ def generate_sites
28
+ @logger.info "Creating data..."
29
+ ActiveRecord::Base.transaction do
30
+ @logger.info " - admins"
31
+ create_initial_admins
32
+ @logger.info " - sites"
33
+ create_sites
34
+ @logger.info " - setting superadmins"
35
+ set_superadmins
36
+ end
37
+ @logger.info "Done."
38
+ end
39
+
40
+ private
41
+
42
+ def create_sites
43
+ @config["sites"].each do |site_slug, site_config|
44
+ site = ::Cas::Site.where(slug: site_slug).first_or_create!
45
+ site.update!(
46
+ domains: site_config["domains"],
47
+ name: site_config["name"]
48
+ )
49
+
50
+ site_config["sections"].each do |key, section|
51
+ model = ::Cas::Section.where(
52
+ slug: key,
53
+ site_id: site.id
54
+ ).first_or_create!(
55
+ name: section["name"],
56
+ section_type: section["type"],
57
+ )
58
+
59
+ model.update!(
60
+ name: section["name"],
61
+ section_type: section["type"],
62
+ )
63
+ end
64
+ end
65
+ end
66
+
67
+ def create_initial_admins
68
+ return if @config["config"]["initial_admins"].blank?
69
+
70
+ @config["config"]["initial_admins"].each do |item|
71
+ ::Cas::User.where(email: item).first_or_create!(
72
+ password: "12345678",
73
+ name: "User",
74
+ roles: ["admin"]
75
+ )
76
+ end
77
+ end
78
+
79
+ def set_superadmins
80
+ return if @config["config"]["superadmins"].blank?
81
+
82
+ updated_users = []
83
+ @config["config"]["superadmins"].each do |email_or_login|
84
+ user = ::Cas::User.where(
85
+ 'cas_users.email = :value OR cas_users.login = :value',
86
+ value: email_or_login
87
+ ).first
88
+
89
+ if user.blank?
90
+ @logger.info "Cannot set user '#{email_or_login}' as superadmin because it doesn't exist"
91
+ next
92
+ end
93
+
94
+ next if updated_users.include?(user.id)
95
+
96
+ user.sites = ::Cas::Site.all
97
+ user.save!
98
+
99
+ updated_users << user.id
100
+ end
101
+ end
102
+ end
103
+ end
@@ -5,26 +5,12 @@ module Cas
5
5
  end
6
6
 
7
7
  def list_order_by
8
- config = YAML.load_file(filename)
9
- sites = config["sites"]
10
- site = sites[@section.site.slug]
11
- section = site["sections"]
12
-
13
- order_field = section.find { |key, value|
14
- key == @section.slug
15
- }[1]['list_order_by']
16
-
8
+ order_field = load_section_config[1]['list_order_by']
17
9
  order_field || ['created_at']
18
10
  end
19
11
 
20
12
  def list_fields
21
- config = YAML.load_file(filename)
22
- sites = config["sites"]
23
- site = sites[@section.site.slug]
24
- section = site["sections"]
25
- fields = section.find { |key, value|
26
- key == @section.slug
27
- }[1]["list_fields"]
13
+ fields = load_section_config[1]["list_fields"]
28
14
  fields || ['title', 'created_at']
29
15
  end
30
16
 
@@ -40,13 +26,7 @@ module Cas
40
26
  end
41
27
 
42
28
  def form_has_field?(field)
43
- config = YAML.load_file(filename)
44
- sites = config["sites"]
45
- site = sites[@section.site.slug]
46
- section = site["sections"]
47
- section_fields = section.find { |key, value|
48
- key == @section.slug
49
- }[1]["fields"]
29
+ section_fields = load_section_config[1]["fields"]
50
30
 
51
31
  Array.wrap(section_fields).any? do |section_field|
52
32
  if section_field.is_a?(Hash)
@@ -63,22 +43,36 @@ module Cas
63
43
  if Rails.env.test?
64
44
  "spec/fixtures/cas.yml"
65
45
  else
66
- "cas.yml"
46
+ Cas::CONFIG_PATH
67
47
  end
68
48
  end
69
49
 
70
50
  def load_field
71
51
  @config ||= begin
72
- config_file = YAML.load_file(filename)
73
- sites = config_file["sites"]
74
- site = sites[@section.site.slug]
75
- section = site["sections"]
76
- field = section.find { |key, value|
77
- key == @section.slug
78
- }
52
+ field = load_section_config
79
53
  (field && field[1]) || {}
80
54
  end
81
55
  end
56
+
57
+ def load_section_config
58
+ begin
59
+ config = YAML.safe_load_file(filename, aliases: true)
60
+ rescue NoMethodError, ArgumentError
61
+ config = YAML.load_file(filename)
62
+ end
63
+
64
+ sites = config["sites"]
65
+ site = sites[@section.site.slug]
66
+
67
+ if site.blank?
68
+ raise(
69
+ Cas::Exceptions::UndefinedSite,
70
+ "Site #{@section.site.slug} is undefined in the #{filename} file."
71
+ )
72
+ end
73
+
74
+ site["sections"].find { |key, value| key == @section.slug }
75
+ end
82
76
  end
83
77
  end
84
78
 
data/lib/cas/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Cas
2
- VERSION = '0.1.3'
2
+ VERSION = '1.0.0.alpha1'
3
3
  end
data/lib/cas.rb CHANGED
@@ -1,7 +1,8 @@
1
1
  require "cas/engine"
2
+ require "cas/exceptions"
2
3
  require "cas/config"
3
4
  require "cas/remote_callbacks"
4
- require "cas/setup"
5
+ require "cas/installation"
5
6
  require "cas/section_config"
6
7
  require "cas/form_field"
7
8
 
@@ -19,4 +20,5 @@ require 'sidekiq'
19
20
  require 'pg_search'
20
21
 
21
22
  module Cas
23
+ CONFIG_PATH = "config/cas.config.yml"
22
24
  end
@@ -0,0 +1,14 @@
1
+ Description:
2
+ Generates new cas.yml and configures database for it.
3
+
4
+ Example:
5
+ bin/rails generate cas:install
6
+
7
+ This will:
8
+ - run Cas migrations
9
+ - add an `/admin` route for Cas
10
+ - create a configuration file in config/cas.config.yml. After you edit
11
+ this file, run
12
+
13
+ bin/rails cas:apply_config
14
+
@@ -0,0 +1,14 @@
1
+ module Cas
2
+ class InstallGenerator < Rails::Generators::Base
3
+ source_root File.expand_path("templates", __dir__)
4
+
5
+ def copy_initializer_file
6
+ rake("db:migrate")
7
+ copy_file "cas.config.yml", Cas::CONFIG_PATH
8
+ route 'mount Cas::Engine, at: "/admin"'
9
+
10
+ puts ""
11
+ puts "Config generated. Now edit `#{Cas::CONFIG_PATH}` and run `bin/rails cas:apply_config`"
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,82 @@
1
+ # CAS CONFIG
2
+ #
3
+ # This file is used to generate the data for the sites you want to manage.
4
+
5
+ # Config: global configuration across all sites
6
+ config:
7
+
8
+ # TODO - clarify what is the initial password
9
+ initial_admins:
10
+ - admin@example.com
11
+
12
+ # Superadmins can create other admins and users. Define which emails or logins
13
+ # you want set as superadmin.
14
+ superadmins:
15
+ - admin@example.com
16
+ - superadmin-login
17
+
18
+ # DEPRECATED
19
+ uploads:
20
+ cache_directory_prefix: 'cache'
21
+ store_directory_prefix: 'uploads'
22
+
23
+ # Sites: define the ones you want to manage. If you have multiple, you will be
24
+ # able to switch between them inside Cas dashboard.
25
+ #
26
+ # Each site has Sections, and each Section has their own Categories.
27
+ sites:
28
+ mysite:
29
+ name: mysite.net
30
+
31
+ # Depending on this, Cas will automatically switch the site it is managing.
32
+ domains:
33
+ - mysite.net
34
+
35
+ # These are entire sections, like 'articles', 'pages', 'ads' etc
36
+ sections:
37
+ news:
38
+ name: news
39
+ type: content
40
+ list_fields:
41
+ - title
42
+ - category
43
+ fields:
44
+ - category
45
+ - tags
46
+ - title
47
+ - summary
48
+ - text
49
+ - images
50
+ - files
51
+ - tags
52
+ - date
53
+ biography:
54
+ name: Biography
55
+ type: content
56
+ fields:
57
+ - title
58
+ - text
59
+ - image
60
+ agenda:
61
+ name: Agenda
62
+ type: content
63
+ accessible_roles:
64
+ - admin
65
+ list_fields:
66
+ - title
67
+ - date_time
68
+ list_order_by:
69
+ - order_field
70
+ fields:
71
+ - title
72
+ - location
73
+ - date:
74
+ language: pt-br
75
+ format:
76
+ - day
77
+ - month
78
+ - year
79
+ - text
80
+ survey:
81
+ name: Survey
82
+ type: survey
@@ -1,4 +1,6 @@
1
- # desc "Explaining what the task does"
2
- # task :cas do
3
- # # Task goes here
4
- # end
1
+ desc "Generate sites based on the YAML config file"
2
+ namespace :cas do
3
+ task apply_config: :environment do
4
+ Cas::Installation.new(logger: Logger.new(STDOUT)).generate_sites
5
+ end
6
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cas-cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 1.0.0.alpha1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexandre de Oliveira
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-05 00:00:00.000000000 Z
11
+ date: 2023-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 5.0.1
19
+ version: 7.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 5.0.1
26
+ version: 7.0.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: pg
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -179,7 +179,7 @@ dependencies:
179
179
  - !ruby/object:Gem::Version
180
180
  version: '0'
181
181
  - !ruby/object:Gem::Dependency
182
- name: tinymce-rails
182
+ name: sidekiq
183
183
  requirement: !ruby/object:Gem::Requirement
184
184
  requirements:
185
185
  - - ">="
@@ -193,7 +193,7 @@ dependencies:
193
193
  - !ruby/object:Gem::Version
194
194
  version: '0'
195
195
  - !ruby/object:Gem::Dependency
196
- name: tinymce-rails-langs
196
+ name: sprockets-rails
197
197
  requirement: !ruby/object:Gem::Requirement
198
198
  requirements:
199
199
  - - ">="
@@ -207,7 +207,21 @@ dependencies:
207
207
  - !ruby/object:Gem::Version
208
208
  version: '0'
209
209
  - !ruby/object:Gem::Dependency
210
- name: sidekiq
210
+ name: tinymce-rails
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ version: '0'
216
+ type: :runtime
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
223
+ - !ruby/object:Gem::Dependency
224
+ name: tinymce-rails-langs
211
225
  requirement: !ruby/object:Gem::Requirement
212
226
  requirements:
213
227
  - - ">="
@@ -226,14 +240,14 @@ dependencies:
226
240
  requirements:
227
241
  - - '='
228
242
  - !ruby/object:Gem::Version
229
- version: 2.7.0
243
+ version: 2.19.1
230
244
  type: :runtime
231
245
  prerelease: false
232
246
  version_requirements: !ruby/object:Gem::Requirement
233
247
  requirements:
234
248
  - - '='
235
249
  - !ruby/object:Gem::Version
236
- version: 2.7.0
250
+ version: 2.19.1
237
251
  - !ruby/object:Gem::Dependency
238
252
  name: roda
239
253
  requirement: !ruby/object:Gem::Requirement
@@ -402,6 +416,20 @@ dependencies:
402
416
  - - ">="
403
417
  - !ruby/object:Gem::Version
404
418
  version: '0'
419
+ - !ruby/object:Gem::Dependency
420
+ name: webrick
421
+ requirement: !ruby/object:Gem::Requirement
422
+ requirements:
423
+ - - ">="
424
+ - !ruby/object:Gem::Version
425
+ version: '0'
426
+ type: :development
427
+ prerelease: false
428
+ version_requirements: !ruby/object:Gem::Requirement
429
+ requirements:
430
+ - - ">="
431
+ - !ruby/object:Gem::Version
432
+ version: '0'
405
433
  description: Description of Cas.
406
434
  email:
407
435
  - chavedomundo@gmail.com
@@ -439,8 +467,9 @@ files:
439
467
  - app/assets/stylesheets/cas/plugins/image_gallery.sass
440
468
  - app/assets/stylesheets/cas/tables.sass
441
469
  - app/assets/stylesheets/cas/typography.sass
442
- - app/assets/stylesheets/cas/vendors/selectize.default.css
470
+ - app/assets/stylesheets/cas/vendors/selectize.css
443
471
  - app/assets/stylesheets/cas/vendors/simplegrid.css
472
+ - app/controllers/cas/activities_controller.rb
444
473
  - app/controllers/cas/api/files_controller.rb
445
474
  - app/controllers/cas/application_controller.rb
446
475
  - app/controllers/cas/devise/sessions_controller.rb
@@ -457,6 +486,7 @@ files:
457
486
  - app/jobs/cas/images/delete_job.rb
458
487
  - app/jobs/cas/images/promote_job.rb
459
488
  - app/jobs/cas/increment_pageviews_job.rb
489
+ - app/models/cas/activity.rb
460
490
  - app/models/cas/application_record.rb
461
491
  - app/models/cas/category.rb
462
492
  - app/models/cas/content.rb
@@ -466,6 +496,7 @@ files:
466
496
  - app/models/cas/sites_user.rb
467
497
  - app/models/cas/user.rb
468
498
  - app/uploaders/file_uploader.rb
499
+ - app/views/cas/activities/index.html.erb
469
500
  - app/views/cas/devise/sessions/new.html.erb
470
501
  - app/views/cas/shared/_error_messages.html.erb
471
502
  - app/views/cas/sites/sections/categories/_form.html.erb
@@ -526,16 +557,22 @@ files:
526
557
  - db/migrate/20171201191059_add_domains_to_cas_site.rb
527
558
  - db/migrate/20171223134308_connects_users_to_sites.rb
528
559
  - db/migrate/20171223143551_make_site_unique.rb
560
+ - db/migrate/20180114124600_create_cas_activities.rb
561
+ - db/migrate/20230220165900_add_subject_title_to_activities.rb
529
562
  - lib/cas.rb
530
563
  - lib/cas/cms.rb
531
564
  - lib/cas/config.rb
532
565
  - lib/cas/engine.rb
566
+ - lib/cas/exceptions.rb
533
567
  - lib/cas/form_field.rb
568
+ - lib/cas/installation.rb
534
569
  - lib/cas/remote_callbacks.rb
535
570
  - lib/cas/section_config.rb
536
- - lib/cas/setup.rb
537
571
  - lib/cas/version.rb
538
572
  - lib/devise/custom_failure.rb
573
+ - lib/generators/cas/USAGE
574
+ - lib/generators/cas/install_generator.rb
575
+ - lib/generators/cas/templates/cas.config.yml
539
576
  - lib/tasks/cas_tasks.rake
540
577
  - lib/templates/erb/scaffold/_form.html.erb
541
578
  homepage: ''
@@ -553,12 +590,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
553
590
  version: '0'
554
591
  required_rubygems_version: !ruby/object:Gem::Requirement
555
592
  requirements:
556
- - - ">="
593
+ - - ">"
557
594
  - !ruby/object:Gem::Version
558
- version: '0'
595
+ version: 1.3.1
559
596
  requirements: []
560
- rubyforge_project:
561
- rubygems_version: 2.6.11
597
+ rubygems_version: 3.1.6
562
598
  signing_key:
563
599
  specification_version: 4
564
600
  summary: Summary of Cas.
data/lib/cas/setup.rb DELETED
@@ -1,60 +0,0 @@
1
- module Cas
2
- class Setup
3
- def install
4
- ActiveRecord::Base.transaction do
5
- config = YAML.load_file(filename)
6
-
7
- config["sites"].each do |site_slug, site_config|
8
- site = ::Cas::Site.where(slug: site_slug).first_or_create
9
- site.update!(
10
- domains: site_config["domains"],
11
- name: site_config["name"]
12
- )
13
-
14
- site_config["sections"].each do |key, section|
15
- model = ::Cas::Section.where(
16
- slug: key,
17
- site_id: site.id
18
- ).first_or_create!(
19
- name: section["name"],
20
- section_type: section["type"],
21
- )
22
-
23
- model.update!(
24
- name: section["name"],
25
- section_type: section["type"],
26
- )
27
- end
28
- end
29
-
30
- if superadmins_emails_or_logins = config["config"]["superadmins"]
31
- updated_users = []
32
- superadmins_emails_or_logins.each do |email_or_login|
33
- user = ::Cas::User.where(
34
- 'cas_users.email = :value OR cas_users.login = :value',
35
- value: email_or_login
36
- ).first
37
-
38
- if user.present?
39
- unless updated_users.include?(user.id)
40
- user.update!(sites: ::Cas::Site.all)
41
- end
42
- updated_users << user.id
43
- end
44
- end
45
- end
46
- end
47
- end
48
-
49
- private
50
-
51
- def filename
52
- if Rails.env.test?
53
- "spec/fixtures/cas.yml"
54
- else
55
- "cas.yml"
56
- end
57
- end
58
- end
59
- end
60
-