rails_cms 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -0
  3. data/README.md +28 -0
  4. data/Rakefile +32 -0
  5. data/app/controllers/cms/admin/audios_controller.rb +24 -0
  6. data/app/controllers/cms/admin/base_controller.rb +5 -0
  7. data/app/controllers/cms/admin/videos_controller.rb +30 -0
  8. data/app/controllers/cms/api/audios_controller.rb +16 -0
  9. data/app/controllers/cms/api/base_controller.rb +5 -0
  10. data/app/controllers/cms/api/video_tags_controller.rb +40 -0
  11. data/app/controllers/cms/api/video_taxons_controller.rb +18 -0
  12. data/app/controllers/cms/api/videos_controller.rb +119 -0
  13. data/app/controllers/cms/base_controller.rb +5 -0
  14. data/app/controllers/cms/my/base_controller.rb +5 -0
  15. data/app/jobs/cms/video_wm_job.rb +9 -0
  16. data/app/models/audio.rb +5 -0
  17. data/app/models/cms/ext/user.rb +24 -0
  18. data/app/models/cms/model/audio.rb +25 -0
  19. data/app/models/cms/model/progression.rb +18 -0
  20. data/app/models/cms/model/video.rb +128 -0
  21. data/app/models/cms/post_tag.rb +3 -0
  22. data/app/models/cms/video_tag.rb +3 -0
  23. data/app/models/cms/video_taxon.rb +3 -0
  24. data/app/models/progression.rb +5 -0
  25. data/app/models/video.rb +9 -0
  26. data/app/views/cms/admin/audios/_filter.html.erb +10 -0
  27. data/app/views/cms/admin/audios/_form.html.erb +6 -0
  28. data/app/views/cms/admin/audios/edit.html.erb +9 -0
  29. data/app/views/cms/admin/audios/index.html.erb +47 -0
  30. data/app/views/cms/admin/audios/new.html.erb +9 -0
  31. data/app/views/cms/admin/audios/show.html.erb +22 -0
  32. data/app/views/cms/admin/base/_nav.html.erb +16 -0
  33. data/app/views/cms/admin/videos/_form.html.erb +8 -0
  34. data/app/views/cms/admin/videos/_search_form.html.erb +6 -0
  35. data/app/views/cms/admin/videos/edit.html.erb +9 -0
  36. data/app/views/cms/admin/videos/index.html.erb +62 -0
  37. data/app/views/cms/admin/videos/new.html.erb +9 -0
  38. data/app/views/cms/admin/videos/show.html.erb +22 -0
  39. data/app/views/cms/api/audios/_audio.json.jbuilder +4 -0
  40. data/app/views/cms/api/audios/index.json.jbuilder +2 -0
  41. data/app/views/cms/api/videos/_detail.json.jbuilder +8 -0
  42. data/app/views/cms/api/videos/_video.json.jbuilder +30 -0
  43. data/app/views/cms/api/videos/index.json.jbuilder +36 -0
  44. data/app/views/cms/api/videos/list.json.jbuilder +9 -0
  45. data/app/views/cms/api/videos/show.json.jbuilder +1 -0
  46. data/config/locales/en.enum.yml +5 -0
  47. data/config/locales/en.notify.yml +7 -0
  48. data/config/locales/zh.enum.yml +9 -0
  49. data/config/locales/zh.notify.yml +7 -0
  50. data/config/routes.rb +23 -0
  51. data/db/migrate/20181203082644_rails_media_init.rb +34 -0
  52. data/lib/rails_cms/config.rb +11 -0
  53. data/lib/rails_cms/engine.rb +10 -0
  54. data/lib/rails_cms.rb +2 -0
  55. metadata +110 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 152a4ad0bd6718e7a70770a5a3d5857ee5f0b4f53acd4d186454c39503a7ebfe
4
+ data.tar.gz: 646a8a77932b4733ec48bfb142475c490923350e0e5d946a7028c73c5d95f611
5
+ SHA512:
6
+ metadata.gz: d9335916cfdf3e2123ec96c576592b83871efd4d2c4274ab8af896175ede6e2c28da7a6409cb92a91d371613b07851e2b73fb948ef174df7b2b071a8315ce65f
7
+ data.tar.gz: 054cd5a4e85dd268b02639e35e85a9a58054771bb2cea8d4a8af8392cd374feca0bc5b8dcefb453681b9124b3e2c25cada32ef1760b8c6b2d14ca64807b6fb7e
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2019-Present Mingyuan Qin <mingyuan0715@foxmail.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # RailsCms
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+ How to use my plugin.
6
+
7
+ ## Installation
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'rails_cms'
12
+ ```
13
+
14
+ And then execute:
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+ ```bash
21
+ $ gem install rails_cms
22
+ ```
23
+
24
+ ## Contributing
25
+ Contribution directions go here.
26
+
27
+ ## License
28
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'RailsCms'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+ load 'rails/tasks/statistics.rake'
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+
32
+ task default: :test
@@ -0,0 +1,24 @@
1
+ module Cms
2
+ class Admin::AudiosController < Admin::BaseController
3
+ before_action :set_audio, only: [:show, :edit, :update, :destroy]
4
+
5
+ def index
6
+ @audios = Audio.page(params[:page])
7
+ end
8
+
9
+ private
10
+ def set_audio
11
+ @audio = Audio.find(params[:id])
12
+ end
13
+
14
+ def audio_params
15
+ params.fetch(:audio, {}).permit(
16
+ :title,
17
+ :state,
18
+ :author_id,
19
+ :media
20
+ )
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,5 @@
1
+ module Cms
2
+ class Admin::BaseController < AdminController
3
+
4
+ end
5
+ end
@@ -0,0 +1,30 @@
1
+ module Cms
2
+ class Admin::VideosController < Admin::BaseController
3
+ before_action :set_video, only: [:show, :edit, :update, :destroy]
4
+
5
+ def index
6
+ q_params = {}.with_indifferent_access
7
+ q_params.merge! params.permit(:author_id)
8
+ @videos = Video.default_where(q_params).order(id: :desc).page(params[:page])
9
+ end
10
+
11
+ private
12
+ def set_video
13
+ @video = Video.find(params[:id])
14
+ end
15
+
16
+ def video_params
17
+ q = params.fetch(:video, {}).permit(
18
+ :title,
19
+ :state,
20
+ :media,
21
+ :cover,
22
+ :author_id,
23
+ :video_taxon_id,
24
+ )
25
+ q.merge!(author_id: current_user.id) if q[:author_id].blank?
26
+ q
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,16 @@
1
+ class Media::Api::AudiosController < Media::Api::BaseController
2
+ before_action :set_audio, only: [:show, :update, :destroy]
3
+
4
+ def index
5
+ @audios = Audio.order(id: :desc).page(params[:page])
6
+ end
7
+
8
+ private
9
+ def set_audio
10
+ @audio = Audio.find(params[:id])
11
+ end
12
+
13
+ def audio_params
14
+ params.fetch(:audio, {})
15
+ end
16
+ end
@@ -0,0 +1,5 @@
1
+ class Media::Api::BaseController < RailsMedia.config.api_class.constantize
2
+
3
+
4
+
5
+ end
@@ -0,0 +1,40 @@
1
+ class Media::Api::VideoTagsController < Media::Api::BaseController
2
+ before_action :set_video_tag, only: [:show, :update]
3
+
4
+ def index
5
+ @video_tags = VideoTag.page(params[:page]).per(params[:per])
6
+
7
+ render json: { video_tags: @video_tags.as_json(only: [:id, :name]) }
8
+ end
9
+
10
+ def show
11
+ render json: @video_tag
12
+ end
13
+
14
+ def create
15
+ @video_tag = VideoTag.new(video_tag_params)
16
+
17
+ if @video_tag.save
18
+ render json: @video_tag, status: :created
19
+ else
20
+ render json: @video_tag.errors, status: :unprocessable_entity
21
+ end
22
+ end
23
+
24
+ def update
25
+ if @video_tag.update(video_tag_params)
26
+ render json: @video_tag
27
+ else
28
+ render json: @video_tag.errors, status: :unprocessable_entity
29
+ end
30
+ end
31
+
32
+ private
33
+ def set_video_tag
34
+ @video_tag = VideoTag.find(params[:id])
35
+ end
36
+
37
+ def video_tag_params
38
+ params.fetch(:video_tag, {}).permit(:name)
39
+ end
40
+ end
@@ -0,0 +1,18 @@
1
+ class Media::Api::VideoTaxonsController < Media::Api::BaseController
2
+ before_action :set_video_taxon, only: [:show]
3
+
4
+ def index
5
+ @video_taxons = VideoTaxon.page(params[:page])
6
+
7
+ render json: { video_taxons: @video_taxons.as_json(only: [:id, :name, :position]) }
8
+ end
9
+
10
+ def show
11
+ render json: @video_taxon
12
+ end
13
+
14
+ private
15
+ def set_video_taxon
16
+ @video_taxon = VideoTaxon.find(params[:id])
17
+ end
18
+ end
@@ -0,0 +1,119 @@
1
+ class Media::Api::VideosController < Media::Api::BaseController
2
+ before_action :set_video, only: [:show, :viewed, :update, :destroy]
3
+ before_action :require_login, only: [:viewed, :starred, :create, :update, :destroy]
4
+
5
+ def index
6
+ q_params = params.permit(:video_taxon_id, :author_id, 'title-like', 'created_at-desc', 'view_count-desc', :id)
7
+ unless q_params[:author_id].to_i == current_user&.id
8
+ q_params.merge! state: 'verified'
9
+ end
10
+
11
+ @videos = Video.with_attached_media.with_attached_cover.includes(:progressions, :comments, :author, :video_taxon).default_where(q_params).order(id: :desc).page(params[:page]).per(params[:per])
12
+
13
+ if params[:subscribe].present?
14
+ @videos = @videos.where("author_id in (?)", current_user.follow_users.pluck(:id))
15
+ end
16
+
17
+ if current_user && params[:starred]
18
+ @star_ids = current_user.stars.where(starred_type: 'Video').pluck(:starred_id)
19
+ @videos = @videos.where(id: @star_ids)
20
+ elsif current_user
21
+ @star_ids = current_user.stars.where(starred_type: 'Video', starred_id: @videos.pluck(:id)).pluck(:starred_id)
22
+ end
23
+ end
24
+
25
+ def list
26
+ ids = []
27
+ if params[:id]
28
+ set_video
29
+ ids << params[:id]
30
+ end
31
+
32
+ q_params = params.permit(:video_taxon_id, :author_id, 'title-like', 'created_at-desc', 'view_count-desc', :per)
33
+ unless q_params[:author_id].to_i == current_user&.id
34
+ q_params.merge! state: 'verified'
35
+ end
36
+
37
+ if @video
38
+ if params[:scope].blank? || params[:scope] == 'pre'
39
+ @pre_videos = @video.pre_videos(q_params)
40
+ ids += @pre_videos.pluck(:id)
41
+ end
42
+ if params[:scope].blank? || params[:scope] == 'next'
43
+ @next_videos = @video.next_videos(q_params)
44
+ ids += @next_videos.pluck(:id)
45
+ end
46
+ else
47
+ @next_videos = Video.default_where(q_params).order(id: :desc).page(params[:page]).per(params[:per])
48
+ ids += @next_videos.pluck(:id)
49
+ end
50
+ if current_user && params[:starred]
51
+ @star_ids = current_user.stars.where(starred_type: 'Video').pluck(:starred_id)
52
+ @next_videos = @next_videos.where(id: @star_ids) if @next_videos
53
+ @pre_videos = @pre_videos.where(id: @star_ids) if @pre_videos
54
+ elsif current_user
55
+ @star_ids = current_user.stars.where(starred_type: 'Video', starred_id: ids).pluck(:starred_id)
56
+ end
57
+ end
58
+
59
+ def starred
60
+ @star_ids = current_user.stars.where(starred_type: 'Video').pluck(:starred_id)
61
+ @videos = Video.where(id: @star_ids).page(params[:page])
62
+ render :index
63
+ end
64
+
65
+ def show
66
+ end
67
+
68
+ def videos
69
+ @videos = user.videos
70
+ render json: { videos: @videos }
71
+ end
72
+
73
+ def viewed
74
+ p = @video.progressions.find_or_initialize_by(user_id: current_user.id)
75
+ p.state = 'done'
76
+ p.save
77
+
78
+ render 'show'
79
+ end
80
+
81
+ def create
82
+ @video = Video.new(video_params)
83
+
84
+ if @video.save
85
+ if current_user
86
+ @star_ids = current_user.stars.where(starred_type: 'Video', starred_id: @video.id).pluck(:starred_id)
87
+ end
88
+ render 'show', status: :created
89
+ else
90
+ render json: @video.errors, status: :unprocessable_entity
91
+ end
92
+ end
93
+
94
+ def update
95
+ if @video.update(video_params)
96
+ render 'show'
97
+ else
98
+ render json: @video.errors, status: :unprocessable_entity
99
+ end
100
+ end
101
+
102
+ private
103
+ def set_video
104
+ @video = Video.find(params[:id])
105
+ if current_user
106
+ @star_ids = current_user.stars.where(starred_type: 'Video', starred_id: @video.id).pluck(:starred_id)
107
+ end
108
+ end
109
+
110
+ def video_params
111
+ params.fetch(:video, {}).permit(
112
+ :title,
113
+ :media,
114
+ :cover,
115
+ :video_taxon_id,
116
+ tag_ids: []
117
+ ).merge(author_id: current_user.id)
118
+ end
119
+ end
@@ -0,0 +1,5 @@
1
+ module Cms
2
+ class BaseController < ApplicationController
3
+
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Cms
2
+ class My::BaseController < MyController
3
+
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ module Cms
2
+ class VideoWmJob < ApplicationJob
3
+
4
+ def perform(video)
5
+ video.water_mark
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ module Cms
2
+ class Audio < ApplicationRecord
3
+ include Model::Audio
4
+ end
5
+ end
@@ -0,0 +1,24 @@
1
+ module RailsMedia::User
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ has_many :videos, foreign_key: :author_id
6
+ end
7
+
8
+ def videos_count
9
+ if defined?(super) && super
10
+ super
11
+ else
12
+ videos.count
13
+ end
14
+ end
15
+
16
+ def video_liked_count
17
+ videos.sum(:liked_count)
18
+ end
19
+
20
+ def video_comments_count
21
+ videos.sum(:comments_count)
22
+ end
23
+
24
+ end
@@ -0,0 +1,25 @@
1
+ module Cms
2
+ module Model::Audio
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ belongs_to :author, class_name: 'Auth::User', optional: true
7
+
8
+ has_one_attached :media
9
+ has_one_attached :cover
10
+ end
11
+
12
+ def media_url
13
+ media.service_url if media.attachment.present?
14
+ end
15
+
16
+ def cover_url
17
+ cover.service_url if cover.attachment.present?
18
+ end
19
+
20
+ def duration
21
+ media_blob.duration
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,18 @@
1
+ module Cms
2
+ module Model::Progression
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ belongs_to :user, class_name: 'Auth::User'
7
+
8
+ belongs_to :progressive, polymorphic: true, counter_cache: :view_count
9
+
10
+ enum state: {
11
+ init: 'init',
12
+ doing: 'doing',
13
+ done: 'done'
14
+ }
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+ module Cms
3
+ module RailsMedia::Video
4
+ WM_PREFIX = '0wm'
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ attribute :share_count, :integer, default: 0
9
+ attribute :view_count, :integer, default: 0
10
+ attribute :liked_count, :integer, default: 0
11
+ attribute :comments_count, :integer, default: 0
12
+ attribute :state, :string, default: 'draft'
13
+
14
+ belongs_to :author, class_name: 'User', optional: true
15
+ belongs_to :video_taxon, optional: true
16
+
17
+ has_many :taggeds, as: :tagging, dependent: :delete_all
18
+ has_many :tags, through: :taggeds
19
+ has_many :attitudes, as: :attitudinal, dependent: :delete_all
20
+ has_many :progressions, as: :progressive, dependent: :delete_all
21
+
22
+ has_one_attached :media
23
+ has_one_attached :cover
24
+
25
+ after_create_commit :doing_water_mark
26
+ after_create_commit :doing_video_tag
27
+
28
+ enum state: {
29
+ draft: 'draft',
30
+ verified: 'verified',
31
+ rejected: 'rejected'
32
+ }
33
+ acts_as_notify :default, only: [:title], methods: [:state_i18n, :cover_url]
34
+ end
35
+
36
+ def do_trigger(params = {})
37
+ self.trigger_to state: params[:state]
38
+
39
+ self.class.transaction do
40
+ self.save!
41
+ to_notification(
42
+ receiver: self.author,
43
+ linked: self,
44
+ verbose: true
45
+ ) if self.author
46
+ end
47
+ end
48
+
49
+ def viewed?(user_id)
50
+ progressions.done.exists?(user_id: user_id)
51
+ end
52
+
53
+ def media_url
54
+ media.blob.service_url if media.attachment.present?
55
+ end
56
+
57
+ def media_wm_url
58
+ if water_mark_job
59
+ QiniuHelper.download_url([WM_PREFIX, self.media_blob&.key].join('_'))
60
+ else
61
+ media_url
62
+ end
63
+ end
64
+
65
+ def cover_url
66
+ cover.blob.service_url if cover.attachment.present?
67
+ end
68
+
69
+ def pre_videos(params = {})
70
+ per = params.delete(:per) || 10
71
+ q = { 'id-gt': self.id }.merge params
72
+
73
+ self.class.default_where(q).order(id: :asc).limit(per)
74
+ end
75
+
76
+ def next_videos(params = {})
77
+ per = params.delete(:per) || 10
78
+ q = { 'id-lt': self.id }.merge params
79
+
80
+ self.class.default_where(q).order(id: :desc).limit(per)
81
+ end
82
+
83
+ def share_url(current_user)
84
+ url_helpers = Rails.application.routes.url_helpers
85
+
86
+ if current_user
87
+ url_helpers.video_url(self.id, user_id: current_user.id)
88
+ else
89
+ url_helpers.video_url(self.id)
90
+ end
91
+ end
92
+
93
+ def water_mark
94
+ if water_mark_job.blank?
95
+ r = QiniuHelper.av_watermark(self.media.key, RailsMedia.config.water_mark_url, gravity: 'North', prefix: WM_PREFIX)
96
+ self.update(water_mark_job: r['persistentId'])
97
+ r
98
+ else
99
+ r = QiniuHelper.prefop(water_mark_job)
100
+ self.update(water_mark_job: r['desc'])
101
+ r
102
+ end
103
+ end
104
+
105
+ def doing_water_mark
106
+ if RailsMedia.config.water_mark
107
+ VideoWmJob.perform_later(self)
108
+ end
109
+ end
110
+
111
+ def cache_entity_logs
112
+ self.update share_count: logs_count('share_video')
113
+ end
114
+
115
+ def doing_video_tag
116
+ reg = /#[^#]+[#|\s]/
117
+ r = self.title.scan(reg)
118
+ tag_str = r.map do |tag|
119
+ tag.gsub(/(^#|#$)/, '')
120
+ end
121
+ tag_ids = tag_str.map do |tag|
122
+ VideoTag.find_or_create_by(name: tag).id
123
+ end
124
+ self.tag_ids = tag_ids
125
+ end
126
+
127
+ end
128
+ end
@@ -0,0 +1,3 @@
1
+ class PostTag < Tag
2
+
3
+ end
@@ -0,0 +1,3 @@
1
+ class VideoTag < Tag
2
+
3
+ end
@@ -0,0 +1,3 @@
1
+ class VideoTaxon < Taxon
2
+
3
+ end
@@ -0,0 +1,5 @@
1
+ module Cms
2
+ class Progression < ApplicationRecord
3
+ include Model::Progression
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ module Cms
2
+ class Video < ApplicationRecord
3
+ include Model::Video
4
+ #include CheckMachine
5
+ include Growth::Ext::Entity
6
+ include Interact::Model::Like
7
+ include Interact::Model::Commentable
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ <div class="ui attached segment">
2
+
3
+ <%= search_form_with do |f| %>
4
+ <div class="fields">
5
+ <%= f.submit 'Search' %>
6
+ </div>
7
+ <% end %>
8
+
9
+ </div>
10
+
@@ -0,0 +1,6 @@
1
+ <%= form_with model: [:admin, @audio], local: true do |f| %>
2
+ <%= render 'shared/error_messages', target: @audio %>
3
+ <%= f.text_field :title %>
4
+ <%= f.file_field :media %>
5
+ <%= f.submit %>
6
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <div class="ui segment breadcrumb">
2
+ <%= link_to 'Back', admin_audios_path, class: 'section' %>
3
+ <div class="divider">/</div>
4
+ <div class="active section">Edit</div>
5
+ </div>
6
+
7
+ <div class="ui segment">
8
+ <%= render 'form' %>
9
+ </div>
@@ -0,0 +1,47 @@
1
+ <div class="ui top attached borderless menu">
2
+ <div class="header item">Admin Audios</div>
3
+ <div class="right menu">
4
+ <div class="item">
5
+ <%= link_to 'New Admin Audio', new_admin_audio_path, class: 'ui teal button' %>
6
+ </div>
7
+ </div>
8
+ </div>
9
+
10
+ <%= render 'filter' %>
11
+
12
+ <table class="ui bottom attached table">
13
+ <thead>
14
+ <tr>
15
+ <th><%= Audio.human_attribute_name(:id) %></th>
16
+ <th><%= Audio.human_attribute_name(:title) %></th>
17
+ <th><%= Audio.human_attribute_name(:state) %></th>
18
+ <th><%= Audio.human_attribute_name(:author) %></th>
19
+ <th>预览</th>
20
+ <th>Actions</th>
21
+ </tr>
22
+ </thead>
23
+ <tbody>
24
+ <% @audios.each do |audio| %>
25
+ <tr>
26
+ <td><%= audio.id %></td>
27
+ <td><%= audio.title %></td>
28
+ <td><%= audio.state %></td>
29
+ <td><%= audio.author.name if audio.author %></td>
30
+ <td><%= link_to '预览', rails_ext_video_path(audio.media.id), target: '_blank' if audio.media.attached? %></td>
31
+ <td class="ui labels">
32
+ <%= link_to admin_audio_path(audio), data: { tooltip: t('.show') }, class: 'ui blue mini icon button' do %>
33
+ <i class="location arrow icon"></i>
34
+ <% end %>
35
+ <%= link_to edit_admin_audio_path(audio), data: { tooltip: t('.edit') }, class: 'ui pink mini icon button' do %>
36
+ <i class="pencil alternate icon"></i>
37
+ <% end %>
38
+ <%= link_to admin_audio_path(audio), method: :delete, data: { tooltip: t('.destroy'), confirm: 'Are you sure?' }, class: 'ui red mini icon button' do %>
39
+ <i class="times icon"></i>
40
+ <% end %>
41
+ </td>
42
+ </tr>
43
+ <% end %>
44
+ </tbody>
45
+ </table>
46
+
47
+ <%= paginate @audios %>
@@ -0,0 +1,9 @@
1
+ <div class="ui segment breadcrumb">
2
+ <%= link_to 'Back', admin_audios_path, class: 'section' %>
3
+ <div class="divider">/</div>
4
+ <div class="active section">Add</div>
5
+ </div>
6
+
7
+ <div class="ui segment">
8
+ <%= render 'form' %>
9
+ </div>
@@ -0,0 +1,22 @@
1
+ <div class="ui segment breadcrumb">
2
+ <%= link_to 'Back', admin_audios_path, class: 'section' %>
3
+ <div class="divider">/</div>
4
+ <div class="active section">Show</div>
5
+ </div>
6
+
7
+ <table class="ui very basic large table">
8
+ <tbody>
9
+ <tr>
10
+ <td class="right aligned"><%= Audio.human_attribute_name(:title) %></td>
11
+ <td><%= @audio.title %></td>
12
+ </tr>
13
+ <tr>
14
+ <td class="right aligned"><%= Audio.human_attribute_name(:state) %></td>
15
+ <td><%= @audio.state %></td>
16
+ </tr>
17
+ <tr>
18
+ <td class="right aligned"><%= Audio.human_attribute_name(:author) %></td>
19
+ <td><%= @audio.author %></td>
20
+ </tr>
21
+ </tbody>
22
+ </table>
@@ -0,0 +1,16 @@
1
+ <div class="ui vertical fluid icon menu">
2
+ <div class="header center link item" id="close_side">
3
+ <i class="content icon"></i>
4
+ </div>
5
+ <div class="item ui dropdown">
6
+ <a class="<%= active_helper(controllers: ['audios', 'videos'], active_class: 'title active', item_class: 'title') %>">
7
+ <i class="file alternate icon"></i>
8
+ <span>资讯</span>
9
+ </a>
10
+ <div class="<%= active_helper(controllers: ['audios', 'videos'], active_class: 'menu content active', item_class: 'menu content') %>">
11
+ <%= link_to '音频管理', admin_audios_path, class: active_helper(controllers: 'audios') %>
12
+ <%= link_to '视频管理', admin_videos_path, class: active_helper(controllers: 'videos') %>
13
+ </div>
14
+ </div>
15
+ </div>
16
+
@@ -0,0 +1,8 @@
1
+ <%= form_with model: [:admin, @video], local: true do |f| %>
2
+ <%= render 'shared/error_messages', target: @video %>
3
+ <%= f.text_field :title %>
4
+ <%= f.collection_select :video_taxon_id, VideoTaxon.all, :id, :name %>
5
+ <%= f.file_field :media %>
6
+ <%= f.file_field :cover %>
7
+ <%= f.submit %>
8
+ <% end %>
@@ -0,0 +1,6 @@
1
+ <%= search_form_with do |f| %>
2
+ <div class="fields">
3
+ <%= f.text_field 'user.name' %>
4
+ <%= f.submit 'Search' %>
5
+ </div>
6
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <div class="ui segment breadcrumb">
2
+ <%= link_to 'Back', admin_videos_path, class: 'section' %>
3
+ <div class="divider">/</div>
4
+ <div class="active section">Edit</div>
5
+ </div>
6
+
7
+ <div class="ui segment">
8
+ <%= render 'form' %>
9
+ </div>
@@ -0,0 +1,62 @@
1
+ <div class="ui top attached borderless menu">
2
+ <div class="header item">Admin Videos</div>
3
+ <div class="right menu">
4
+ <div class="item">
5
+ <%= link_to 'New Admin Video', new_admin_video_path, class: 'ui teal button' %>
6
+ </div>
7
+ </div>
8
+ </div>
9
+
10
+ <div class="ui attached segment">
11
+ <%= render 'search_form' %>
12
+ </div>
13
+
14
+ <table class="ui bottom attached table">
15
+ <thead>
16
+ <tr>
17
+ <th><%= Video.human_attribute_name(:id) %></th>
18
+ <th><%= Video.human_attribute_name(:title) %></th>
19
+ <th><%= Video.human_attribute_name(:cover) %></th>
20
+ <th><%= Video.human_attribute_name(:media) %></th>
21
+ <th><%= Video.human_attribute_name(:state) %></th>
22
+ <th><%= Video.human_attribute_name(:author_id) %></th>
23
+ <th><%= Video.human_attribute_name(:created_at) %></th>
24
+ <th>Actions</th>
25
+ </tr>
26
+ </thead>
27
+ <tbody>
28
+ <% @videos.each do |video| %>
29
+ <tr>
30
+ <td><%= video.id %></td>
31
+ <td><%= video.title %></td>
32
+ <td><%= image_tag video.cover, class: 'ui small image' if video.cover.attached? %></td>
33
+ <td><%= link_to '预览', rails_ext_video_path(video.media&.id), target: '_blank' %></td>
34
+ <td class="ui labels">
35
+ <label class="ui label"><%= video.state_i18n %></label>
36
+ <div class="ui mini buttons">
37
+ <%= link_to t('.approve'), new_check_path('Video', video.id, state: Video.states[:verified]), remote: true, class: 'ui positive button' %>
38
+ <div class="or"></div>
39
+ <%= link_to t('.reject'), new_check_path('Video', video.id, state: Video.states[:rejected]), remote: true, class: 'ui negative button' %>
40
+ </div>
41
+ </td>
42
+ <td>
43
+ <%= link_to video.author.name, admin_user_path(video.author_id) if video.author %>
44
+ </td>
45
+ <td><time><%= video.created_at.to_s(:rfc822) %></time></td>
46
+ <td class="ui labels">
47
+ <%= link_to admin_video_path(video), data: { tooltip: t('.show') }, class: 'ui blue mini icon button' do %>
48
+ <i class="location arrow icon"></i>
49
+ <% end %>
50
+ <%= link_to edit_admin_video_path(video), data: { tooltip: t('.edit') }, class: 'ui pink mini icon button' do %>
51
+ <i class="pencil alternate icon"></i>
52
+ <% end %>
53
+ <%= link_to admin_video_path(video), method: :delete, data: { tooltip: t('.destroy'), confirm: 'Are you sure?' }, class: 'ui red mini icon button' do %>
54
+ <i class="times icon"></i>
55
+ <% end %>
56
+ </td>
57
+ </tr>
58
+ <% end %>
59
+ </tbody>
60
+ </table>
61
+
62
+ <%= paginate @videos %>
@@ -0,0 +1,9 @@
1
+ <div class="ui segment breadcrumb">
2
+ <%= link_to 'Back', admin_videos_path, class: 'section' %>
3
+ <div class="divider">/</div>
4
+ <div class="active section">Add</div>
5
+ </div>
6
+
7
+ <div class="ui segment">
8
+ <%= render 'form' %>
9
+ </div>
@@ -0,0 +1,22 @@
1
+ <div class="ui segment breadcrumb">
2
+ <%= link_to 'Back', admin_videos_path, class: 'section' %>
3
+ <div class="divider">/</div>
4
+ <div class="active section">Show</div>
5
+ </div>
6
+
7
+ <table class="ui very basic large table">
8
+ <tbody>
9
+ <tr>
10
+ <td class="right aligned"><%= Video.human_attribute_name(:title) %></td>
11
+ <td><%= @video.title %></td>
12
+ </tr>
13
+ <tr>
14
+ <td class="right aligned"><%= Video.human_attribute_name(:state) %></td>
15
+ <td><%= @video.state %></td>
16
+ </tr>
17
+ <tr>
18
+ <td class="right aligned"><%= Video.human_attribute_name(:author_id) %></td>
19
+ <td><%= @video.author_id %></td>
20
+ </tr>
21
+ </tbody>
22
+ </table>
@@ -0,0 +1,4 @@
1
+ json.extract! audio, :id, :title, :cover_url, :media_url, :duration
2
+ if audio.author
3
+ json.author audio.author, :id, :name, :avatar_url
4
+ end
@@ -0,0 +1,2 @@
1
+ json.audios @audios, partial: 'audio', as: :audio
2
+ json.partial! 'api/shared/pagination', items: @audios
@@ -0,0 +1,8 @@
1
+ json.partial! 'video', video: video
2
+ json.tags video.tags do |tag|
3
+ json.extract! tag, :id, :name
4
+ end
5
+ json.comments video.comments do |comment|
6
+ json.extract! comment, :id, :title, :content, :state, :score, :liked_count, :created_at
7
+ json.commenter comment.user, :id, :name, :avatar_url
8
+ end
@@ -0,0 +1,30 @@
1
+ json.extract! video,
2
+ :id,
3
+ :title,
4
+ :cover_url,
5
+ :view_count,
6
+ :liked_count,
7
+ :share_count,
8
+ :created_at,
9
+ :rewardable
10
+ json.share_url video.share_url(current_user)
11
+ json.comments_count video.comments.count
12
+ if video.author
13
+ json.author video.author, :id, :name, :avatar_url
14
+ end
15
+ json.media do
16
+ json.extract! video.media.metadata, *(video.media.metadata.keys & ['height', 'width'])
17
+ json.duration video.media.blob.duration
18
+ json.duration_str video.media.blob.duration_str
19
+ json.url video.media.service_url
20
+ json.wm_url video.media_wm_url
21
+ end
22
+ if video.video_taxon
23
+ json.video_taxon video.video_taxon, :id, :name
24
+ end
25
+ if current_user
26
+ json.starred @star_ids.include?(video.id)
27
+ json.viewed video.viewed?(current_user.id)
28
+ json.liked video.liked?(current_user.id)
29
+ json.rewardable_codes video.rewardable_codes(current_user.id)
30
+ end
@@ -0,0 +1,36 @@
1
+ json.partial! 'api/shared/pagination', items: @videos
2
+
3
+ json.videos do
4
+ json.array! @videos do |video|
5
+ json.id video.id
6
+ json.title video.title
7
+ json.cover_url video.cover_url
8
+ json.view_count video.view_count
9
+ json.liked_count video.liked_count
10
+ json.share_count video.share_count
11
+ json.created_at video.created_at
12
+ json.rewardable video.rewardable
13
+ json.share_url video.share_url(current_user)
14
+ json.comments_count video.comments.count
15
+ if video.author
16
+ json.author video.author, :id, :name, :avatar_url
17
+ end
18
+ json.media do
19
+ json.extract! video.media.metadata, *(video.media.metadata.keys & ['height', 'width'])
20
+ json.duration video.media.blob.duration
21
+ json.duration_str video.media.blob.duration_str
22
+ json.url video.media.service_url
23
+ json.wm_url video.media_wm_url
24
+ end
25
+ if video.video_taxon
26
+ json.video_taxon video.video_taxon, :id, :name
27
+ end
28
+ if current_user
29
+ json.starred @star_ids.include?(video.id)
30
+ json.viewed video.viewed?(current_user.id)
31
+ json.liked video.liked?(current_user.id)
32
+ json.rewardable_codes video.rewardable_codes(current_user.id)
33
+ end
34
+ end
35
+ end
36
+
@@ -0,0 +1,9 @@
1
+ if defined?(@video)
2
+ json.video @video, partial: 'detail', as: :video
3
+ end
4
+ if defined?(@pre_videos)
5
+ json.pre @pre_videos, partial: 'detail', as: :video
6
+ end
7
+ if defined?(@next_videos)
8
+ json.next @next_videos, partial: 'detail', as: :video
9
+ end
@@ -0,0 +1 @@
1
+ json.video @video, partial: 'detail', as: :video
@@ -0,0 +1,5 @@
1
+ en:
2
+ activerecord:
3
+ attributes:
4
+ taxon/type:
5
+ VideoTaxon: Video Taxon
@@ -0,0 +1,7 @@
1
+ en:
2
+ activerecord:
3
+ notify:
4
+ video:
5
+ default:
6
+ title: '%{title}'
7
+ body: Your video has been %{state_i18n}
@@ -0,0 +1,9 @@
1
+ zh:
2
+ activerecord:
3
+ attributes:
4
+ taxon/type:
5
+ VideoTaxon: 视频分类
6
+ video/state:
7
+ draft: 待审核
8
+ verified: 已通过
9
+ rejected: 未通过
@@ -0,0 +1,7 @@
1
+ zh:
2
+ activerecord:
3
+ notify:
4
+ video:
5
+ default:
6
+ title: 您好!您提交的视频审核%{state_i18n}
7
+ body: '%{title}'
data/config/routes.rb ADDED
@@ -0,0 +1,23 @@
1
+ Rails.application.routes.draw do
2
+
3
+ namespace :cms, defaults: { business: 'cms' } do
4
+ resources :videos, on: [:show]
5
+
6
+ scope :api, module: 'media/api', as: :api do
7
+ resources :videos do
8
+ get :list, on: :collection
9
+ get :starred, on: :collection
10
+ patch :viewed, on: :member
11
+ end
12
+ resources :video_taxons
13
+ resources :video_tags
14
+ resources :audios, only: [:index]
15
+ end
16
+
17
+ namespace :admin, defaults: { namespace: 'admin' } do
18
+ resources :videos
19
+ resources :audios
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,34 @@
1
+ class RailsMediaInit < ActiveRecord::Migration[5.2]
2
+ def change
3
+
4
+ create_table :videos do |t|
5
+ t.references :author
6
+ t.references :video_taxon
7
+ t.string :title
8
+ t.string :state
9
+ t.integer :liked_count
10
+ t.integer :view_count
11
+ t.integer :comments_count
12
+ t.string :water_mark_job
13
+ t.timestamps
14
+ end
15
+
16
+ create_table :audios do |t|
17
+ t.references :author
18
+ t.string :title
19
+ t.string :state
20
+ t.timestamps
21
+ end
22
+
23
+ create_table :progressions do |t|
24
+ t.references :user
25
+ t.references :progressive, polymorphic: true
26
+ t.float :rate
27
+ t.float :time
28
+ t.float :duration
29
+ t.string :state
30
+ t.timestamps
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,11 @@
1
+ require 'active_support/configurable'
2
+
3
+ module RailsCms
4
+ include ActiveSupport::Configurable
5
+
6
+ configure do |config|
7
+ config.water_mark = false
8
+ config.water_mark_url = 'http://cloud.1314-edu.com/watermark.gif'
9
+ end
10
+
11
+ end
@@ -0,0 +1,10 @@
1
+ module RailsCms
2
+ class Engine < ::Rails::Engine
3
+
4
+ config.autoload_paths += Dir[
5
+ "#{config.root}/app/models/tag",
6
+ "#{config.root}/app/models/taxon"
7
+ ]
8
+
9
+ end
10
+ end
data/lib/rails_cms.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'rails_cms/engine'
2
+ require 'rails_cms/config'
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails_cms
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - qinmingyuan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-10-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails_extend
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: Description of RailsCms.
28
+ email:
29
+ - mingyuan0715@foxmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - LICENSE
35
+ - README.md
36
+ - Rakefile
37
+ - app/controllers/cms/admin/audios_controller.rb
38
+ - app/controllers/cms/admin/base_controller.rb
39
+ - app/controllers/cms/admin/videos_controller.rb
40
+ - app/controllers/cms/api/audios_controller.rb
41
+ - app/controllers/cms/api/base_controller.rb
42
+ - app/controllers/cms/api/video_tags_controller.rb
43
+ - app/controllers/cms/api/video_taxons_controller.rb
44
+ - app/controllers/cms/api/videos_controller.rb
45
+ - app/controllers/cms/base_controller.rb
46
+ - app/controllers/cms/my/base_controller.rb
47
+ - app/jobs/cms/video_wm_job.rb
48
+ - app/models/audio.rb
49
+ - app/models/cms/ext/user.rb
50
+ - app/models/cms/model/audio.rb
51
+ - app/models/cms/model/progression.rb
52
+ - app/models/cms/model/video.rb
53
+ - app/models/cms/post_tag.rb
54
+ - app/models/cms/video_tag.rb
55
+ - app/models/cms/video_taxon.rb
56
+ - app/models/progression.rb
57
+ - app/models/video.rb
58
+ - app/views/cms/admin/audios/_filter.html.erb
59
+ - app/views/cms/admin/audios/_form.html.erb
60
+ - app/views/cms/admin/audios/edit.html.erb
61
+ - app/views/cms/admin/audios/index.html.erb
62
+ - app/views/cms/admin/audios/new.html.erb
63
+ - app/views/cms/admin/audios/show.html.erb
64
+ - app/views/cms/admin/base/_nav.html.erb
65
+ - app/views/cms/admin/videos/_form.html.erb
66
+ - app/views/cms/admin/videos/_search_form.html.erb
67
+ - app/views/cms/admin/videos/edit.html.erb
68
+ - app/views/cms/admin/videos/index.html.erb
69
+ - app/views/cms/admin/videos/new.html.erb
70
+ - app/views/cms/admin/videos/show.html.erb
71
+ - app/views/cms/api/audios/_audio.json.jbuilder
72
+ - app/views/cms/api/audios/index.json.jbuilder
73
+ - app/views/cms/api/videos/_detail.json.jbuilder
74
+ - app/views/cms/api/videos/_video.json.jbuilder
75
+ - app/views/cms/api/videos/index.json.jbuilder
76
+ - app/views/cms/api/videos/list.json.jbuilder
77
+ - app/views/cms/api/videos/show.json.jbuilder
78
+ - config/locales/en.enum.yml
79
+ - config/locales/en.notify.yml
80
+ - config/locales/zh.enum.yml
81
+ - config/locales/zh.notify.yml
82
+ - config/routes.rb
83
+ - db/migrate/20181203082644_rails_media_init.rb
84
+ - lib/rails_cms.rb
85
+ - lib/rails_cms/config.rb
86
+ - lib/rails_cms/engine.rb
87
+ homepage: https://github.com/work-design/rails_cms
88
+ licenses:
89
+ - MIT
90
+ metadata: {}
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubygems_version: 3.2.22
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: Summary of RailsCms.
110
+ test_files: []