cas-cms 0.1.3 → 1.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
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
-