polivalente 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -0
- data/app/assets/images/polivalente/user-sample.jpg +0 -0
- data/app/controllers/polivalente/application_controller.rb +3 -0
- data/app/controllers/polivalente/autocomplete_controller.rb +21 -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/models/polivalente/user.rb +27 -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/routes.rb +8 -0
- 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 +9 -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/engine.rb +16 -0
- data/lib/polivalente/user_locale.rb +24 -0
- data/lib/polivalente/version.rb +1 -1
- data/lib/polivalente.rb +19 -1
- metadata +96 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9f64f29b6f512a3d0a252d028648066293adf4ed36a56c4b2b19924e8f529e89
|
4
|
+
data.tar.gz: 044f17f768a0c1132c182257dfc7a6ea6b5a825b22df8772751f82f5227e6984
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b20d5aca11a7dfe9445df9256f86e9ff7cc7b7e7f4e8b5dc2c0ba2cc163adfc68f9ba9d396eee704c9102d777351dde8a403d7d13595cb06a0bfdbdf3fddb9ec
|
7
|
+
data.tar.gz: c609c2b70bce6a1448dc8b69b923c0424eef481d6214922bef626276cccf571464162bd65080ee6136726dc9dd0270faa8c8543e314e253bb82f44cca6501605
|
data/README.md
CHANGED
Binary file
|
@@ -0,0 +1,21 @@
|
|
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
|
+
@users = User.all.latest
|
12
|
+
render json: @users, status: 200
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def force_json
|
18
|
+
request.format = :json
|
19
|
+
end
|
20
|
+
end
|
21
|
+
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::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::trash_ttl.from_now)
|
29
|
+
.perform_later(self)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module Polivalente
|
2
2
|
class User < ApplicationRecord
|
3
|
+
include Sortable
|
4
|
+
|
3
5
|
# Include default devise modules. Others available are:
|
4
6
|
# :registerable, :validatable,
|
5
7
|
# :timeoutable, and :omniauthable
|
@@ -10,11 +12,36 @@ module Polivalente
|
|
10
12
|
:recoverable,
|
11
13
|
:lockable,
|
12
14
|
:trackable
|
15
|
+
|
16
|
+
has_one_attached :photo
|
13
17
|
|
14
18
|
validates_length_of :first_name, minimum: 2, maximum: 20
|
15
19
|
validates_length_of :last_name, minimum: 2, maximum: 20
|
16
20
|
validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }
|
17
21
|
validates_uniqueness_of :email
|
18
22
|
validates_length_of :password, minimum: 8
|
23
|
+
|
24
|
+
# A user account is considered spam/abandoned if:
|
25
|
+
# - The account has existed for at least N days
|
26
|
+
# - The account was never confirmed/activated
|
27
|
+
# - The the user never signed in to their account
|
28
|
+
#
|
29
|
+
# These records should be deleted from the database periodically
|
30
|
+
scope :spam, -> {
|
31
|
+
where("created_at <= ? AND sign_in_count <= 1 AND confirmed_at IS NULL", Time.zone.now - Polivalente::spam_account_ttl.days)
|
32
|
+
}
|
33
|
+
|
34
|
+
# A user account is inactive if:
|
35
|
+
# - The account has not been signed in to for more than X days
|
36
|
+
# These users should be notified about their account state
|
37
|
+
scope :inactive, -> {
|
38
|
+
where("current_sign_in_at <= ?", Time.zone.now - Polivalente::inactive_account_ttl.days)
|
39
|
+
}
|
40
|
+
|
41
|
+
scope :unconfirmed, -> { where(:confirmed_at => nil)}
|
42
|
+
|
43
|
+
def name
|
44
|
+
"#{first_name} #{last_name}"
|
45
|
+
end
|
19
46
|
end
|
20
47
|
end
|
data/config/routes.rb
CHANGED
@@ -1,3 +1,11 @@
|
|
1
1
|
Polivalente::Engine.routes.draw do
|
2
|
+
# Health check
|
3
|
+
resources :ping, only: [:index]
|
4
|
+
|
2
5
|
devise_for :users, class_name: "Polivalente::User"
|
6
|
+
|
7
|
+
namespace :autocomplete, defaults: { format: :json } do
|
8
|
+
get 'tags', as: :tag_completion
|
9
|
+
get 'users', as: :user_completion
|
10
|
+
end
|
3
11
|
end
|
@@ -1,14 +1,13 @@
|
|
1
1
|
class CreateUsers < ActiveRecord::Migration[7.0]
|
2
2
|
def change
|
3
3
|
create_table :users do |t|
|
4
|
-
t.string :slug, null: false, unique: true
|
5
4
|
t.string :first_name, null: false, index: true
|
6
5
|
t.string :last_name, null: false, index: true
|
7
6
|
t.boolean :is_admin, null: false, index: true, default: false
|
8
7
|
t.boolean :is_verified, null: false, index: true, default: false
|
9
8
|
|
10
9
|
## Devise::DatabaseAuthenticatable
|
11
|
-
t.string :email, null: false, default: "", unique: true
|
10
|
+
t.string :email, null: false, default: "", index: { unique: true }
|
12
11
|
t.string :encrypted_password, null: false, default: ""
|
13
12
|
|
14
13
|
## Devise::Recoverable
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class CreateTaggings < ActiveRecord::Migration[7.0]
|
2
|
+
def change
|
3
|
+
create_table :taggings do |t|
|
4
|
+
t.belongs_to :tag, null: false, foreign_key: { on_delete: :cascade }
|
5
|
+
t.references :taggable, null: false, polymorphic: true, index: true
|
6
|
+
|
7
|
+
t.timestamps
|
8
|
+
|
9
|
+
t.index [:tag_id, :taggable_id, :taggable_type], unique: true, name: "index_unique_tagged_item"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# This migration comes from active_storage (originally 20170806125915)
|
2
|
+
class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
|
3
|
+
def change
|
4
|
+
create_table :active_storage_blobs do |t|
|
5
|
+
t.string :key, null: false
|
6
|
+
t.string :filename, null: false
|
7
|
+
t.string :content_type
|
8
|
+
t.text :metadata
|
9
|
+
t.string :service_name, null: false
|
10
|
+
t.bigint :byte_size, null: false
|
11
|
+
t.string :checksum, null: false
|
12
|
+
t.datetime :created_at, null: false
|
13
|
+
|
14
|
+
t.index [ :key ], unique: true
|
15
|
+
end
|
16
|
+
|
17
|
+
create_table :active_storage_attachments do |t|
|
18
|
+
t.string :name, null: false
|
19
|
+
t.references :record, null: false, polymorphic: true, index: false
|
20
|
+
t.references :blob, null: false
|
21
|
+
|
22
|
+
t.datetime :created_at, null: false
|
23
|
+
|
24
|
+
t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
|
25
|
+
t.foreign_key :active_storage_blobs, column: :blob_id
|
26
|
+
end
|
27
|
+
|
28
|
+
create_table :active_storage_variant_records do |t|
|
29
|
+
t.belongs_to :blob, null: false, index: false
|
30
|
+
t.string :variation_digest, null: false
|
31
|
+
|
32
|
+
t.index %i[ blob_id variation_digest ], name: "index_active_storage_variant_records_uniqueness", unique: true
|
33
|
+
t.foreign_key :active_storage_blobs, column: :blob_id
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# This migration comes from action_mailbox (originally 20180917164000)
|
2
|
+
class CreateActionMailboxTables < ActiveRecord::Migration[6.0]
|
3
|
+
def change
|
4
|
+
create_table :action_mailbox_inbound_emails do |t|
|
5
|
+
t.integer :status, default: 0, null: false
|
6
|
+
t.string :message_id, null: false
|
7
|
+
t.string :message_checksum, null: false
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
|
11
|
+
t.index [ :message_id, :message_checksum ], name: "index_action_mailbox_inbound_emails_uniqueness", unique: true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# This migration comes from action_text (originally 20180528164100)
|
2
|
+
class CreateActionTextTables < ActiveRecord::Migration[6.0]
|
3
|
+
def change
|
4
|
+
create_table :action_text_rich_texts do |t|
|
5
|
+
t.string :name, null: false
|
6
|
+
t.text :body, size: :long
|
7
|
+
t.references :record, polymorphic: true, null: false, index: false
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
|
11
|
+
t.index [ :record_type, :record_id, :name ], name: "index_action_text_rich_texts_uniqueness", unique: true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class CreateComments < ActiveRecord::Migration[7.0]
|
2
|
+
def change
|
3
|
+
create_table :comments do |t|
|
4
|
+
t.belongs_to :user, null: false, index: true, foreign_key: { on_delete: :cascade }
|
5
|
+
t.references :commentable, null: false, index: true, polymorphic: true
|
6
|
+
t.string :content_hash, null: false
|
7
|
+
t.boolean :is_private, null: false, default: false
|
8
|
+
t.datetime :discarded_at, null: true, index: true
|
9
|
+
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateReactions < ActiveRecord::Migration[7.0]
|
2
|
+
def change
|
3
|
+
create_table :reactions do |t|
|
4
|
+
t.belongs_to :user, null: false, index: true, foreign_key: { on_delete: :cascade }
|
5
|
+
t.references :reactable, null: false, polymorphic: true
|
6
|
+
t.integer :kind, null: false, index: true, limit: 20
|
7
|
+
t.json :data, null: true, default: "{}"
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
|
11
|
+
t.index [:user_id, :kind, :reactable_type, :reactable_id], unique: true, name: "index_unique_user_reactions"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class CreateTrash < ActiveRecord::Migration[6.1]
|
2
|
+
def change
|
3
|
+
create_table :trash do |t|
|
4
|
+
t.belongs_to :user, null: false, foreign_key: { on_delete: :cascade }
|
5
|
+
t.references :trashable, null: false, polymorphic: true, index: true
|
6
|
+
|
7
|
+
t.timestamps
|
8
|
+
|
9
|
+
t.index [:user_id, :trashable_id, :trashable_type], unique: true, name: "index_unique_trash_item"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class CreateArchives < ActiveRecord::Migration[7.0]
|
2
|
+
def change
|
3
|
+
create_table :archives do |t|
|
4
|
+
t.belongs_to :user, null: false, foreign_key: { on_delete: :cascade }
|
5
|
+
t.references :archivable, null: false, polymorphic: true, index: true
|
6
|
+
|
7
|
+
t.timestamps
|
8
|
+
|
9
|
+
t.index [:user_id, :archivable_id, :archivable_type], unique: true, name: "index_unique_archive_item"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
Description:
|
2
|
+
Stubs out a new Stimulus controller.
|
3
|
+
|
4
|
+
This generator accepts one argument, the name of the controller, CamelCased or under_scored.
|
5
|
+
|
6
|
+
Example:
|
7
|
+
`rails generate stimulus Thing`
|
8
|
+
|
9
|
+
This will create a new Stimulus controller at `app/javascript/controllers/thing_controller.js`
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class StimulusGenerator < Rails::Generators::NamedBase
|
2
|
+
# Source: https://github.com/DavidColby/rails-stimulus-generator
|
3
|
+
source_root File.expand_path('templates', __dir__)
|
4
|
+
|
5
|
+
check_class_collision suffix: "Controller"
|
6
|
+
|
7
|
+
def create_controller_directory
|
8
|
+
empty_directory("app/javascript/controllers") unless File.directory?("app/javascript/controllers")
|
9
|
+
end
|
10
|
+
|
11
|
+
def create_controller
|
12
|
+
template("controller.js", File.join("app/javascript/controllers/#{file_name}_controller.js"))
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import { Controller } from 'stimulus'
|
2
|
+
|
3
|
+
export default class extends Controller {
|
4
|
+
static targets = []
|
5
|
+
|
6
|
+
initialize() {
|
7
|
+
// Called once, when the controller is first instantiated
|
8
|
+
}
|
9
|
+
|
10
|
+
connect() {
|
11
|
+
// Called any time the controller is connected to the DOM
|
12
|
+
}
|
13
|
+
|
14
|
+
disconnect() {
|
15
|
+
// Called any time the controller is disconnected from the DOM
|
16
|
+
}
|
17
|
+
}
|
data/lib/polivalente/engine.rb
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
module Polivalente
|
2
2
|
class Engine < ::Rails::Engine
|
3
3
|
isolate_namespace Polivalente
|
4
|
+
|
5
|
+
config.generators do |g|
|
6
|
+
g.scaffold_stylesheet false
|
7
|
+
g.assets false
|
8
|
+
g.test_framework :rspec
|
9
|
+
g.fixture_replacement :factory_bot
|
10
|
+
g.factory_bot dir: "spec/factories"
|
11
|
+
end
|
12
|
+
|
13
|
+
initializer "polivalente.factories", after: "factory_bot.set_factory_paths" do
|
14
|
+
FactoryBot.definition_file_paths << File.expand_path('../../../spec/factories', __FILE__) if defined?(FactoryBot)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Do not prefix table names with `polivantente_`
|
19
|
+
def self.table_name_prefix
|
4
20
|
end
|
5
21
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Polivalente
|
2
|
+
module UserLocale
|
3
|
+
|
4
|
+
protected
|
5
|
+
|
6
|
+
def set_user_locale!
|
7
|
+
@user_locale ||= params[:locale] ||
|
8
|
+
session[:locale] ||
|
9
|
+
extracted_locale_from_header ||
|
10
|
+
I18n.default_locale
|
11
|
+
|
12
|
+
I18n.locale = @user_locale
|
13
|
+
|
14
|
+
rescue I18n::InvalidLocale
|
15
|
+
I18n.locale = @user_locale = I18n.default_locale
|
16
|
+
end
|
17
|
+
|
18
|
+
def extracted_locale_from_header
|
19
|
+
request.headers['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]/).first.to_sym
|
20
|
+
rescue NoMethodError
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/polivalente/version.rb
CHANGED
data/lib/polivalente.rb
CHANGED
@@ -1,15 +1,33 @@
|
|
1
1
|
require "polivalente/version"
|
2
2
|
require "polivalente/railtie"
|
3
3
|
require "polivalente/engine"
|
4
|
+
|
5
|
+
# Third-party
|
6
|
+
|
7
|
+
require "active_model_serializers"
|
4
8
|
require "devise"
|
9
|
+
require "discard"
|
10
|
+
require "factory_bot_rails"
|
5
11
|
|
6
12
|
module Polivalente
|
7
13
|
# Attributes
|
14
|
+
mattr_accessor :inactive_account_ttl
|
15
|
+
mattr_accessor :spam_account_ttl
|
16
|
+
mattr_accessor :supported_locales
|
17
|
+
mattr_accessor :trash_ttl
|
18
|
+
|
19
|
+
self.inactive_account_ttl = 60.days
|
20
|
+
self.spam_account_ttl = 4.days
|
21
|
+
self.supported_locales = [:en]
|
22
|
+
self.trash_ttl = 30.days
|
23
|
+
|
24
|
+
# Modules
|
25
|
+
autoload :UserLocale, "polivalente/user_locale"
|
8
26
|
|
9
27
|
# Configuration
|
10
28
|
|
29
|
+
# do not prefix table names with `polivantente_`
|
11
30
|
def self.table_name_prefix
|
12
|
-
# do not prefix table names with `polivantente_`
|
13
31
|
end
|
14
32
|
|
15
33
|
def self.setup
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: polivalente
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leo Neto
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-02-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -30,6 +30,20 @@ dependencies:
|
|
30
30
|
- - "~>"
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '7.0'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: active_model_serializers
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0.10'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0.10'
|
33
47
|
- !ruby/object:Gem::Dependency
|
34
48
|
name: devise
|
35
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -44,6 +58,20 @@ dependencies:
|
|
44
58
|
- - "~>"
|
45
59
|
- !ruby/object:Gem::Version
|
46
60
|
version: '4.8'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: discard
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '1.2'
|
68
|
+
type: :runtime
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '1.2'
|
47
75
|
- !ruby/object:Gem::Dependency
|
48
76
|
name: factory_bot_rails
|
49
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,6 +86,20 @@ dependencies:
|
|
58
86
|
- - "~>"
|
59
87
|
- !ruby/object:Gem::Version
|
60
88
|
version: '6.2'
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: faker
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '2.19'
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '2.19'
|
61
103
|
- !ruby/object:Gem::Dependency
|
62
104
|
name: rspec-rails
|
63
105
|
requirement: !ruby/object:Gem::Requirement
|
@@ -83,21 +125,73 @@ files:
|
|
83
125
|
- README.md
|
84
126
|
- Rakefile
|
85
127
|
- app/assets/config/polivalente_manifest.js
|
128
|
+
- app/assets/images/polivalente/user-sample.jpg
|
86
129
|
- app/assets/stylesheets/polivalente/application.css
|
87
130
|
- app/controllers/polivalente/application_controller.rb
|
131
|
+
- app/controllers/polivalente/autocomplete_controller.rb
|
132
|
+
- app/controllers/polivalente/ping_controller.rb
|
88
133
|
- app/helpers/polivalente/application_helper.rb
|
134
|
+
- app/helpers/polivalente/color_helper.rb
|
135
|
+
- app/helpers/polivalente/enum_helper.rb
|
136
|
+
- app/helpers/polivalente/gravatar_helper.rb
|
137
|
+
- app/helpers/polivalente/tags_helper.rb
|
89
138
|
- app/jobs/polivalente/application_job.rb
|
139
|
+
- app/jobs/polivalente/clean_trash_job.rb
|
90
140
|
- app/mailers/polivalente/application_mailer.rb
|
141
|
+
- app/models/concerns/polivalente/archivable.rb
|
142
|
+
- app/models/concerns/polivalente/archiver.rb
|
143
|
+
- app/models/concerns/polivalente/commentable.rb
|
144
|
+
- app/models/concerns/polivalente/commentator.rb
|
145
|
+
- app/models/concerns/polivalente/content_hashable.rb
|
146
|
+
- app/models/concerns/polivalente/reactable.rb
|
147
|
+
- app/models/concerns/polivalente/reactor.rb
|
148
|
+
- app/models/concerns/polivalente/sortable.rb
|
149
|
+
- app/models/concerns/polivalente/taggable.rb
|
150
|
+
- app/models/concerns/polivalente/trashable.rb
|
151
|
+
- app/models/concerns/polivalente/trasher.rb
|
152
|
+
- app/models/concerns/polivalente/user_owned.rb
|
153
|
+
- app/models/concerns/polivalente/visibility.rb
|
91
154
|
- app/models/polivalente/application_record.rb
|
155
|
+
- app/models/polivalente/archive.rb
|
156
|
+
- app/models/polivalente/comment.rb
|
157
|
+
- app/models/polivalente/reaction.rb
|
158
|
+
- app/models/polivalente/tag.rb
|
159
|
+
- app/models/polivalente/tagging.rb
|
160
|
+
- app/models/polivalente/trash.rb
|
92
161
|
- app/models/polivalente/user.rb
|
162
|
+
- app/serializers/polivalente/comment_serializer.rb
|
163
|
+
- app/serializers/polivalente/reaction_serializer.rb
|
164
|
+
- app/serializers/polivalente/tag_serializer.rb
|
165
|
+
- app/serializers/polivalente/tagging_serializer.rb
|
166
|
+
- app/serializers/polivalente/user_serializer.rb
|
93
167
|
- app/views/layouts/polivalente/application.html.erb
|
94
168
|
- config/initializers/devise.rb
|
95
169
|
- config/locales/devise.en.yml
|
96
170
|
- config/routes.rb
|
97
171
|
- db/migrate/20220124153504_create_users.rb
|
172
|
+
- db/migrate/20220125040905_create_tags.rb
|
173
|
+
- db/migrate/20220125040916_create_taggings.rb
|
174
|
+
- db/migrate/20220125040920_create_active_storage_tables.active_storage.rb
|
175
|
+
- db/migrate/20220125040921_create_action_mailbox_tables.action_mailbox.rb
|
176
|
+
- db/migrate/20220125040922_create_action_text_tables.action_text.rb
|
177
|
+
- db/migrate/20220125044901_create_comments.rb
|
178
|
+
- db/migrate/20220125144339_create_reactions.rb
|
179
|
+
- db/migrate/20220125144342_create_trash.rb
|
180
|
+
- db/migrate/20220130033524_create_archives.rb
|
181
|
+
- lib/generators/polivalente/install/install_generator.rb
|
182
|
+
- lib/generators/rails/concern/USAGE
|
183
|
+
- lib/generators/rails/concern/concern_generator.rb
|
184
|
+
- lib/generators/rails/concern/templates/concern.rb
|
185
|
+
- lib/generators/rails/stimulus/USAGE
|
186
|
+
- lib/generators/rails/stimulus/stimulus_generator.rb
|
187
|
+
- lib/generators/rails/stimulus/templates/controller.js
|
188
|
+
- lib/generators/rails/validator/USAGE
|
189
|
+
- lib/generators/rails/validator/templates/validator.rb
|
190
|
+
- lib/generators/rails/validator/validator_generator.rb
|
98
191
|
- lib/polivalente.rb
|
99
192
|
- lib/polivalente/engine.rb
|
100
193
|
- lib/polivalente/railtie.rb
|
194
|
+
- lib/polivalente/user_locale.rb
|
101
195
|
- lib/polivalente/version.rb
|
102
196
|
- lib/tasks/polivalente_tasks.rake
|
103
197
|
homepage: https://github.com/oleoneto/polivalente
|