rails_cms 0.0.1
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.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +32 -0
- data/app/controllers/cms/admin/audios_controller.rb +24 -0
- data/app/controllers/cms/admin/base_controller.rb +5 -0
- data/app/controllers/cms/admin/videos_controller.rb +30 -0
- data/app/controllers/cms/api/audios_controller.rb +16 -0
- data/app/controllers/cms/api/base_controller.rb +5 -0
- data/app/controllers/cms/api/video_tags_controller.rb +40 -0
- data/app/controllers/cms/api/video_taxons_controller.rb +18 -0
- data/app/controllers/cms/api/videos_controller.rb +119 -0
- data/app/controllers/cms/base_controller.rb +5 -0
- data/app/controllers/cms/my/base_controller.rb +5 -0
- data/app/jobs/cms/video_wm_job.rb +9 -0
- data/app/models/audio.rb +5 -0
- data/app/models/cms/ext/user.rb +24 -0
- data/app/models/cms/model/audio.rb +25 -0
- data/app/models/cms/model/progression.rb +18 -0
- data/app/models/cms/model/video.rb +128 -0
- data/app/models/cms/post_tag.rb +3 -0
- data/app/models/cms/video_tag.rb +3 -0
- data/app/models/cms/video_taxon.rb +3 -0
- data/app/models/progression.rb +5 -0
- data/app/models/video.rb +9 -0
- data/app/views/cms/admin/audios/_filter.html.erb +10 -0
- data/app/views/cms/admin/audios/_form.html.erb +6 -0
- data/app/views/cms/admin/audios/edit.html.erb +9 -0
- data/app/views/cms/admin/audios/index.html.erb +47 -0
- data/app/views/cms/admin/audios/new.html.erb +9 -0
- data/app/views/cms/admin/audios/show.html.erb +22 -0
- data/app/views/cms/admin/base/_nav.html.erb +16 -0
- data/app/views/cms/admin/videos/_form.html.erb +8 -0
- data/app/views/cms/admin/videos/_search_form.html.erb +6 -0
- data/app/views/cms/admin/videos/edit.html.erb +9 -0
- data/app/views/cms/admin/videos/index.html.erb +62 -0
- data/app/views/cms/admin/videos/new.html.erb +9 -0
- data/app/views/cms/admin/videos/show.html.erb +22 -0
- data/app/views/cms/api/audios/_audio.json.jbuilder +4 -0
- data/app/views/cms/api/audios/index.json.jbuilder +2 -0
- data/app/views/cms/api/videos/_detail.json.jbuilder +8 -0
- data/app/views/cms/api/videos/_video.json.jbuilder +30 -0
- data/app/views/cms/api/videos/index.json.jbuilder +36 -0
- data/app/views/cms/api/videos/list.json.jbuilder +9 -0
- data/app/views/cms/api/videos/show.json.jbuilder +1 -0
- data/config/locales/en.enum.yml +5 -0
- data/config/locales/en.notify.yml +7 -0
- data/config/locales/zh.enum.yml +9 -0
- data/config/locales/zh.notify.yml +7 -0
- data/config/routes.rb +23 -0
- data/db/migrate/20181203082644_rails_media_init.rb +34 -0
- data/lib/rails_cms/config.rb +11 -0
- data/lib/rails_cms/engine.rb +10 -0
- data/lib/rails_cms.rb +2 -0
- 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,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,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
|
data/app/models/audio.rb
ADDED
@@ -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
|
data/app/models/video.rb
ADDED
@@ -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,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,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,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,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 @@
|
|
1
|
+
json.video @video, partial: 'detail', as: :video
|
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
|
data/lib/rails_cms.rb
ADDED
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: []
|