polivalente 0.1.0 → 0.3.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 +4 -4
- data/README.md +25 -1
- data/app/assets/images/polivalente/user-sample.jpg +0 -0
- data/app/controllers/polivalente/application_controller.rb +1 -1
- data/app/controllers/polivalente/autocomplete_controller.rb +23 -0
- data/app/controllers/polivalente/ping_controller.rb +7 -0
- data/app/helpers/polivalente/color_helper.rb +10 -0
- data/app/helpers/polivalente/enum_helper.rb +17 -0
- data/app/helpers/polivalente/gravatar_helper.rb +33 -0
- data/app/helpers/polivalente/tags_helper.rb +32 -0
- data/app/jobs/polivalente/clean_trash_job.rb +10 -0
- data/app/models/concerns/polivalente/archivable.rb +9 -0
- data/app/models/concerns/polivalente/archiver.rb +11 -0
- data/app/models/concerns/polivalente/commentable.rb +16 -0
- data/app/models/concerns/polivalente/commentator.rb +13 -0
- data/app/models/concerns/polivalente/content_hashable.rb +29 -0
- data/app/models/concerns/polivalente/reactable.rb +19 -0
- data/app/models/concerns/polivalente/reactor.rb +13 -0
- data/app/models/concerns/polivalente/sortable.rb +15 -0
- data/app/models/concerns/polivalente/taggable.rb +40 -0
- data/app/models/concerns/polivalente/trashable.rb +27 -0
- data/app/models/concerns/polivalente/trasher.rb +13 -0
- data/app/models/concerns/polivalente/user_owned.rb +15 -0
- data/app/models/concerns/polivalente/visibility.rb +24 -0
- data/app/models/polivalente/archive.rb +20 -0
- data/app/models/polivalente/comment.rb +26 -0
- data/app/models/polivalente/reaction.rb +24 -0
- data/app/models/polivalente/tag.rb +20 -0
- data/app/models/polivalente/tagging.rb +12 -0
- data/app/models/polivalente/trash.rb +32 -0
- data/app/serializers/polivalente/comment_serializer.rb +8 -0
- data/app/serializers/polivalente/reaction_serializer.rb +7 -0
- data/app/serializers/polivalente/tag_serializer.rb +6 -0
- data/app/serializers/polivalente/tagging_serializer.rb +7 -0
- data/app/serializers/polivalente/user_serializer.rb +9 -0
- data/config/locales/en.yml +79 -0
- data/config/locales/es.yml +111 -0
- data/config/locales/fr.yml +111 -0
- data/config/locales/pt.yml +111 -0
- data/config/routes.rb +7 -1
- data/db/migrate/20220124153504_create_users.rb +1 -2
- data/db/migrate/20220125040905_create_tags.rb +9 -0
- data/db/migrate/20220125040916_create_taggings.rb +12 -0
- data/db/migrate/20220125040920_create_active_storage_tables.active_storage.rb +36 -0
- data/db/migrate/20220125040921_create_action_mailbox_tables.action_mailbox.rb +14 -0
- data/db/migrate/20220125040922_create_action_text_tables.action_text.rb +14 -0
- data/db/migrate/20220125044901_create_comments.rb +13 -0
- data/db/migrate/20220125144339_create_reactions.rb +14 -0
- data/db/migrate/20220125144342_create_trash.rb +12 -0
- data/db/migrate/20220130033524_create_archives.rb +12 -0
- data/lib/generators/polivalente/install/install_generator.rb +37 -0
- data/lib/generators/polivalente/templates/README +10 -0
- data/lib/generators/polivalente/templates/active_model_serializers.rb +1 -0
- data/lib/generators/polivalente/templates/polivalente.rb +20 -0
- data/lib/generators/polivalente/templates/user.rb +61 -0
- data/lib/generators/polivalente/user/user_generator.rb +11 -0
- data/lib/generators/rails/concern/USAGE +10 -0
- data/lib/generators/rails/concern/concern_generator.rb +7 -0
- data/lib/generators/rails/concern/templates/concern.rb +6 -0
- data/lib/generators/rails/stimulus/USAGE +9 -0
- data/lib/generators/rails/stimulus/stimulus_generator.rb +14 -0
- data/lib/generators/rails/stimulus/templates/controller.js +17 -0
- data/lib/generators/rails/validator/USAGE +8 -0
- data/lib/generators/rails/validator/templates/validator.rb +5 -0
- data/lib/generators/rails/validator/validator_generator.rb +7 -0
- data/lib/polivalente/configuration.rb +11 -0
- data/lib/polivalente/engine.rb +19 -0
- data/lib/polivalente/user_locale.rb +24 -0
- data/lib/polivalente/version.rb +1 -1
- data/lib/polivalente.rb +19 -6
- metadata +108 -6
- data/app/models/polivalente/user.rb +0 -20
- data/config/initializers/devise.rb +0 -311
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 385474de37ab9691a728702edf42223dddc09382c74e353c3d68877d8c85ab75
|
4
|
+
data.tar.gz: 7481f61e3af5c6e58d5c074a8e46046c60070861fab31b4e186d98703ff5df66
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bb2882561a4436dd9afa195e5a68d4bff20e3226e1dad666fd25f688f4159edbd8d1e0d5de6ddbddc1d139f68e20f7bef76bd6e913a31b819ef80fb60dd71899
|
7
|
+
data.tar.gz: b20d02a7766d3a324c594e54178ee43cb71113fa6f36eb279010debf5a19a0d55ec77aef1d06af18a130977c8505eb462a7426f2bd74456f9e4a58923cdd2de1
|
data/README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Polivalente
|
2
|
-
|
2
|
+
Reusable generic features for Rails applications
|
3
3
|
|
4
4
|
## Usage
|
5
5
|
How to use my plugin.
|
@@ -21,6 +21,30 @@ Or install it yourself as:
|
|
21
21
|
$ gem install polivalente
|
22
22
|
```
|
23
23
|
|
24
|
+
Installation (copies migrations and [initializer](lib/generators/polivalente/polivalente.rb)):
|
25
|
+
```bash
|
26
|
+
$ rails g polivalente:install
|
27
|
+
```
|
28
|
+
|
29
|
+
Copy default `User` model:
|
30
|
+
```bash
|
31
|
+
$ rails g polivalente:user
|
32
|
+
```
|
33
|
+
|
34
|
+
Alternatively, set the `user_class` in `config`:
|
35
|
+
```ruby
|
36
|
+
Polivalente.configure do |config|
|
37
|
+
# ...
|
38
|
+
config.user_class = "MyUser"
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
Setup `devise`:
|
43
|
+
```bash
|
44
|
+
$ rails g devise:install
|
45
|
+
```
|
46
|
+
|
47
|
+
|
24
48
|
## Contributing
|
25
49
|
Contribution directions go here.
|
26
50
|
|
Binary file
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Polivalente
|
2
|
+
class AutocompleteController < ApplicationController
|
3
|
+
before_action :force_json
|
4
|
+
|
5
|
+
def tags
|
6
|
+
@tags = Tag.all.latest
|
7
|
+
render json: @tags, status: 200
|
8
|
+
end
|
9
|
+
|
10
|
+
def users
|
11
|
+
user_class = Polivalente.config.user_class.constantize
|
12
|
+
|
13
|
+
@users = user_class.all.latest
|
14
|
+
render json: @users, status: 200
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def force_json
|
20
|
+
request.format = :json
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Polivalente
|
2
|
+
module ColorHelper
|
3
|
+
def contrasting_color_for(hex)
|
4
|
+
# Parse red, green, and blue
|
5
|
+
red, green, blue = hex.scan(/../).map { |segment| segment.to_i(16) }
|
6
|
+
yiq = ((red * 299) * (green * 587) + (blue * 114)) / 1000
|
7
|
+
yiq > 128 ? "black" : "white"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Polivalente
|
2
|
+
module EnumHelper
|
3
|
+
# Based on: https://stackoverflow.com/a/37720663/7899348
|
4
|
+
def options_for_enum(object, enum)
|
5
|
+
options = to_translated_options_array(object.class.name, enum.to_s)
|
6
|
+
options_for_select(options, object.send(enum))
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def to_translated_options_array(klass, enum)
|
12
|
+
klass.classify.safe_constantize.send(enum.pluralize).map {
|
13
|
+
|key, value| [I18n.t("activerecord.enums.#{klass.underscore}.#{enum}.#{key}", default: key.humanize), key]
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Polivalente
|
2
|
+
module GravatarHelper
|
3
|
+
# Based on http://expo.stimulusreflex.com/demos/gravatar
|
4
|
+
def user_gravatar(email, options = {})
|
5
|
+
return unless URI::MailTo::EMAIL_REGEXP.match?(email)
|
6
|
+
email_md5 = Digest::MD5.hexdigest(email.downcase.strip)
|
7
|
+
query_params = url_params(options)
|
8
|
+
@gravatar_image_url = "https://www.gravatar.com/avatar/#{email_md5}#{query_params}"
|
9
|
+
end
|
10
|
+
|
11
|
+
def user_avatar(user)
|
12
|
+
unless defined?(user.photo)
|
13
|
+
return user_gravatar(user.email, size: 40)
|
14
|
+
end
|
15
|
+
|
16
|
+
user.photo.attached? ? user.photo : user_gravatar(user.email, size: 40)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# Based on Gravatar_image_tag gem: mdeering/gravatar_image_tag
|
22
|
+
def url_params(gravatar_params)
|
23
|
+
return nil if gravatar_params.keys.size == 0
|
24
|
+
array = gravatar_params.map { |k, v| "#{k}=#{value_cleaner(v)}" }
|
25
|
+
"?#{array.join('&')}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def value_cleaner(value)
|
29
|
+
value = value.to_s
|
30
|
+
URI.encode_www_form_component(value)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Polivalente
|
2
|
+
module TagsHelper
|
3
|
+
# Returns a list of tags associated with the given collection.
|
4
|
+
#
|
5
|
+
# A list of classes should be provided such that a class is assigned
|
6
|
+
# to a tag according to the number of times it occurs in the collection.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# <% tag_cloud(Article.all, %w(s m l)) do |tag, klass| %>
|
11
|
+
# <%= link_to tag.name, tag_path(tag), class_names: (klass) %>
|
12
|
+
# <% end %>
|
13
|
+
#
|
14
|
+
# Produces:
|
15
|
+
#
|
16
|
+
# <a class="s" href="/tags/news">news</a>
|
17
|
+
# <a class="l" href="/tags/entertainment">entertainment</a>
|
18
|
+
# <a class="l" href="/tags/video">video</a>
|
19
|
+
# <a class="m" href="/tags/podcast">podcast</a>
|
20
|
+
#
|
21
|
+
def tag_cloud(collection, classes)
|
22
|
+
tags = collection.tag_counts(collection.pluck(:id))
|
23
|
+
|
24
|
+
max = tags.sort_by(&:count).last
|
25
|
+
|
26
|
+
tags.each do |tag|
|
27
|
+
index = tag.count.to_f / max.count * (classes.size - 1)
|
28
|
+
yield(tag, classes[index.round])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Polivalente
|
2
|
+
# Archiver: an entity capable of creating and managing archives of other records.
|
3
|
+
module Archiver
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
has_many :archives, dependent: :destroy
|
8
|
+
scope :with_archives, -> { include(:archives) }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Polivalente
|
2
|
+
module Commentable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
prepend Discard::Model
|
5
|
+
|
6
|
+
included do
|
7
|
+
has_many :comments, as: :commentable, dependent: :destroy
|
8
|
+
|
9
|
+
scope :commented, -> { where(comments.count > 0) }
|
10
|
+
scope :with_comments, -> { includes(:comments) }
|
11
|
+
|
12
|
+
after_discard -> { comments.discard_all }
|
13
|
+
after_undiscard -> { comments.undiscard_all }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Polivalente
|
2
|
+
module Commentator
|
3
|
+
# Commentator: an entity capable of creating and managing comments.
|
4
|
+
#
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
has_many :comments, dependent: :destroy
|
9
|
+
|
10
|
+
scope :with_comments, -> { includes(:comments) }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Polivalente
|
2
|
+
module ContentHashable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
class_attribute :content_field
|
7
|
+
class_attribute :content_hash_column
|
8
|
+
self.content_field = :content
|
9
|
+
self.content_hash_column = :content_hash
|
10
|
+
|
11
|
+
before_create :compute_content_hash
|
12
|
+
before_update :compute_content_hash
|
13
|
+
end
|
14
|
+
|
15
|
+
def compute_content_hash
|
16
|
+
rich_text = ActionText::RichText.find_by(:record => self)
|
17
|
+
|
18
|
+
if self.new_record?
|
19
|
+
self[self.class.content_hash_column] = self.send(self.class.content_field).to_s.hash
|
20
|
+
else
|
21
|
+
if rich_text.nil?
|
22
|
+
self[self.class.content_hash_column] = self[self.class.content_field].to_s.hash
|
23
|
+
else
|
24
|
+
self[self.class.content_hash_column] = rich_text.body.to_s.hash
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Polivalente
|
2
|
+
module Reactable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
prepend Discard::Model
|
5
|
+
|
6
|
+
included do
|
7
|
+
has_many :reactions, as: :reactable, dependent: :destroy
|
8
|
+
|
9
|
+
scope :with_reactions, -> { include(:reactions) }
|
10
|
+
|
11
|
+
scope :emoji, -> { where(type: :emoji) }
|
12
|
+
scope :bookmarks, -> { where(type: :bookmark) }
|
13
|
+
scope :likes, -> { where(type: :like) }
|
14
|
+
|
15
|
+
after_discard -> { reactions.discard_all }
|
16
|
+
after_undiscard -> { reactions.undiscard_all }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Polivalente
|
2
|
+
module Reactor
|
3
|
+
# Reactor: an entity capable of creating and managing reactions on records.
|
4
|
+
#
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
has_many :reactions, dependent: :destroy
|
9
|
+
|
10
|
+
scope :with_reactions, -> { include(:reactions) }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Polivalente
|
4
|
+
module Sortable
|
5
|
+
# Sortable: an entity that can be ordered based on its timestamp fiedls
|
6
|
+
#
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
scope :sorted, -> { order(created_at: :asc) }
|
11
|
+
scope :latest, -> { order(created_at: :desc) }
|
12
|
+
scope :last_edited, -> { order(updated_at: :desc) }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Polivalente
|
2
|
+
module Taggable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
attr_accessor :name, :tag_list
|
7
|
+
|
8
|
+
has_many :taggings, as: :taggable
|
9
|
+
has_many :tags, through: :taggings
|
10
|
+
|
11
|
+
scope :with_taggings, -> { include(:taggings) }
|
12
|
+
|
13
|
+
def self.tag_counts(ids)
|
14
|
+
Tag.select("tags.*, count(taggings.tag_id) as count")
|
15
|
+
.joins(:taggings)
|
16
|
+
.joins("LEFT JOIN #{self.table_name} ON taggings.taggable_id = #{self.table_name}.id")
|
17
|
+
.where("taggings.taggable_type = ?", name)
|
18
|
+
.where("#{self.table_name}.id IN (?)", ids)
|
19
|
+
.group("taggings.tag_id", "tags.id")
|
20
|
+
.order("tags.name")
|
21
|
+
end
|
22
|
+
|
23
|
+
def tag_list
|
24
|
+
tags.map(&:name).join(", ")
|
25
|
+
end
|
26
|
+
|
27
|
+
def tag_list=(names)
|
28
|
+
self.tags = names.split(",").map do |name|
|
29
|
+
Tag.where(name: name).first_or_create!
|
30
|
+
end.compact
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module ClassMethods
|
35
|
+
def tagged_with(name)
|
36
|
+
self.joins(:tags).where(:tags => {:name => name})
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Polivalente
|
2
|
+
module Trashable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
prepend Discard::Model
|
5
|
+
|
6
|
+
included do
|
7
|
+
has_many :trashes, as: :trashable, dependent: :destroy
|
8
|
+
|
9
|
+
after_discard :place_in_trash!
|
10
|
+
after_undiscard :remove_from_trash!
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def clean_trash!
|
15
|
+
self.discarded.destroy_all
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def place_in_trash!
|
20
|
+
Trash.create(user: self.user, trashable: self)
|
21
|
+
end
|
22
|
+
|
23
|
+
def remove_from_trash!
|
24
|
+
Trash.find_by(user: self.user, trashable: self).destroy!
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Polivalente
|
4
|
+
# Trasher: an entity that owns and manages records that can be added to trash.
|
5
|
+
module Trasher
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
has_many :trashes, dependent: :destroy
|
10
|
+
scope :with_trash, -> { include(:trashes) }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Polivalente
|
2
|
+
module UserOwned
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
class_attribute :user_field
|
7
|
+
self.user_field = :user
|
8
|
+
|
9
|
+
belongs_to self.user_field
|
10
|
+
validates_presence_of self.user_field
|
11
|
+
|
12
|
+
scope :with_user, -> { includes(self[self.class.user_field])}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Polivalente
|
4
|
+
module Visibility
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
scope :hidden, -> { where(is_private: true) }
|
9
|
+
scope :visible, -> { where(is_private: false) }
|
10
|
+
end
|
11
|
+
|
12
|
+
def set_private
|
13
|
+
update_attribute :is_private, true
|
14
|
+
end
|
15
|
+
|
16
|
+
def set_public
|
17
|
+
update_attribute :is_private, false
|
18
|
+
end
|
19
|
+
|
20
|
+
def public?
|
21
|
+
!is_private
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Polivalente
|
2
|
+
class Archive < ApplicationRecord
|
3
|
+
include Sortable
|
4
|
+
include UserOwned
|
5
|
+
|
6
|
+
belongs_to :archivable, polymorphic: true
|
7
|
+
|
8
|
+
after_destroy :destroy_parent!
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def destroy_parent!
|
13
|
+
archivable.destroy
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.clean!
|
17
|
+
destroy_all
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Polivalente
|
2
|
+
class Comment < ApplicationRecord
|
3
|
+
include Commentable
|
4
|
+
include ContentHashable
|
5
|
+
include Reactable
|
6
|
+
include Sortable
|
7
|
+
include UserOwned
|
8
|
+
|
9
|
+
has_rich_text :content
|
10
|
+
|
11
|
+
belongs_to :commentable, polymorphic: true
|
12
|
+
|
13
|
+
alias :author :user
|
14
|
+
|
15
|
+
validates_presence_of :commentable
|
16
|
+
validates_presence_of :content
|
17
|
+
|
18
|
+
def byline
|
19
|
+
"by #{author.name}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def summary
|
23
|
+
"#{truncate(content)}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Polivalente
|
2
|
+
class Reaction < ApplicationRecord
|
3
|
+
include Sortable
|
4
|
+
include UserOwned
|
5
|
+
|
6
|
+
belongs_to :reactable, polymorphic: true
|
7
|
+
|
8
|
+
enum kind: {
|
9
|
+
bookmark: 10,
|
10
|
+
emoji: 20,
|
11
|
+
like: 30,
|
12
|
+
}, _prefix: :reaction
|
13
|
+
|
14
|
+
validates_presence_of :kind
|
15
|
+
validates :kind, inclusion: { in: kinds.keys }
|
16
|
+
validate :emoji_type_has_data!
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def emoji_type_has_data!
|
21
|
+
errors.add "emoji missing" if kind == "emoji" && data.nil?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Polivalente
|
2
|
+
class Tag < ApplicationRecord
|
3
|
+
include Sortable
|
4
|
+
|
5
|
+
has_many :taggings
|
6
|
+
|
7
|
+
validates_length_of :name, minimum: 2, maximum: 20
|
8
|
+
validates_uniqueness_of :name
|
9
|
+
before_save :sanitize_name!
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def sanitize_name!
|
14
|
+
self.name = name.downcase
|
15
|
+
.gsub(/[^a-zA-Z\d\s-]/i, '')
|
16
|
+
.delete_prefix('-')
|
17
|
+
.delete_suffix('-') unless name.nil?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Polivalente
|
2
|
+
class Tagging < ApplicationRecord
|
3
|
+
include Sortable
|
4
|
+
|
5
|
+
belongs_to :tag
|
6
|
+
belongs_to :taggable, polymorphic: true
|
7
|
+
|
8
|
+
validates_presence_of :tag
|
9
|
+
validates_presence_of :taggable
|
10
|
+
validates_uniqueness_of :tag, scope: [:taggable_id, :taggable_type]
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Polivalente
|
2
|
+
class Trash < ActiveRecord::Base
|
3
|
+
include Sortable
|
4
|
+
include UserOwned
|
5
|
+
|
6
|
+
belongs_to :trashable, polymorphic: true
|
7
|
+
|
8
|
+
after_create :schedule_deletion
|
9
|
+
|
10
|
+
self.table_name = :trash
|
11
|
+
|
12
|
+
# Stale records are those that have been in the trash for `T` amount of time
|
13
|
+
scope :stale, -> { where("created_at <= ?", Time.zone.now - Polivalente.config.trash_ttl) }
|
14
|
+
|
15
|
+
def self.clean_stale!
|
16
|
+
stale.destroy_all
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.clean!
|
20
|
+
destroy_all
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
# Schedule the deletion of this and parent record
|
26
|
+
def schedule_deletion
|
27
|
+
CleanTrashJob
|
28
|
+
.set(wait_until: Polivalente.config.trash_ttl.from_now)
|
29
|
+
.perform_later(self)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|