decidim-user_fields 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0d7b7ee3b6215fc3fb95f7d1501369650d051fe38e731492fc9ce5628ad75577
4
+ data.tar.gz: c4d1e5eb6e11d01ea3a61196a73ad107c34b96c43c52c6ab388ba733e98ad00d
5
+ SHA512:
6
+ metadata.gz: 8adddf951a431b592d6062f04b31478c0ddeef718b492b78ddadaf995b1bf2b208f2fa8937a47bad2009f4410b4518845d264fff123477ab72c6622719a4b5d7
7
+ data.tar.gz: cfda033cd73225d2834d8617f8898f248a97ddae6a4f8d32a7997315340a2dec0bd133ba065c62b277a2806ddf96a31eafa082b10b1ef7a83ba815a644d3bb37
data/README.md ADDED
@@ -0,0 +1,121 @@
1
+ <h1 align="center"><img src="https://github.com/octree-gva/meta/blob/main/decidim/static/header.png?raw=true" alt="Decidim - Octree Participatory democracy on a robust and open source solution" /></h1>
2
+ <h4 align="center">
3
+ <a href="https://www.octree.ch">Octree</a> |
4
+ <a href="https://octree.ch/en/contact-us/">Contact Us</a> |
5
+ <a href="https://blog.octree.ch">Our Blog (FR)</a><br/><br/>
6
+ <a href="https://decidim.org">Decidim</a> |
7
+ <a href="https://docs.decidim.org/en/">Decidim Docs</a> |
8
+ <a href="https://meta.decidim.org">Participatory Governance (meta decidim)</a><br/><br/>
9
+ <a href="https://matrix.to/#/+decidim:matrix.org">Decidim Community (Matrix+Element.io)</a>
10
+ </h4>
11
+ <p align="center">
12
+ <a href="https://participe.gland.ch">
13
+ <img
14
+ src="https://github.com/octree-gva/meta/blob/main/decidim/static/participe_gland.png?raw=true"
15
+ alt="Participe Gland — Donnez vie à vos idées avec le budget participatif" />
16
+ </a>
17
+ <a href="https://mkutano.community"><img src="https://github.com/octree-gva/decidim-module-mkutano_custom_registration_flow/blob/main/mkutano-logo.png?raw=true" alt="MKUTANO is a participatory platform where black canadians can effectively & democratically organize at scale" /></a>
18
+ <a href="https://opencollective.com/voca">
19
+ <img
20
+ src="https://github.com/octree-gva/meta/blob/main/decidim/static/opencollective_chip.png?raw=true"
21
+ alt="Voca – Open-Source SaaS platform for Decidim" />
22
+ </a>
23
+ </p>
24
+
25
+
26
+ # Decidim User Fields
27
+ Add custom user fields, through configuration file and without migration.
28
+ This module aims to configure in a blast new fields for subscription and profile edition. It supports:
29
+
30
+ - User registration
31
+ - User profiles
32
+ - User invitations.
33
+
34
+ ⚠️ It **does not support**:
35
+
36
+ - Omniauth registrations
37
+
38
+ ## Setup the module
39
+ Add the gem to your gemfile
40
+ ```
41
+ gem "decidim-user_fields"
42
+ ```
43
+
44
+ Run bundle
45
+ ```
46
+ bundle install
47
+ ```
48
+
49
+ Create an initializer `config/initializers/custom_user_fields.rb`
50
+ ```
51
+ Decidim::CustomUserFields.configure do |config|
52
+ config.add_field :birthdate, type: :date, required: true
53
+ config.add_field :province, type: :select, options: [:vd, :vs, :ar], default: :vd, required: true
54
+ config.add_field :adress, type: :textarea, required: false, rows: 10
55
+ config.add_field :purpose, type: :text, required: false
56
+ end
57
+ ```
58
+
59
+ ### Available field types
60
+
61
+ **`:date`**
62
+
63
+ parameters:
64
+ * `required`: must choose a date
65
+ * `min`: date in ISO8601 where the user can not select before
66
+ * `max`: date in ISO8601 where the user can not select after
67
+
68
+ **`:textarea`**
69
+
70
+ parameters:
71
+ * `required`: if the field is required
72
+ * `min`: minimal length
73
+ * `max`: maximal length
74
+ * `rows`: how much rows the field should display
75
+
76
+ **`:text`**
77
+
78
+ parameters:
79
+ * `required`: if the field is required
80
+
81
+ ### Labels
82
+ Labels are translated, and are under the traduction scope `decidim.custom_user_fields`.
83
+ Example of a `fr.yml` file:
84
+
85
+ ```yml
86
+ fr:
87
+ activemodel:
88
+ attributes:
89
+ user:
90
+ birthday: "Birthday"
91
+ adress: "Addresse"
92
+ purpose: "Raison d'être ici"
93
+ province: "Canton"
94
+ decidim:
95
+ custom_user_fields:
96
+ province:
97
+ options:
98
+ vd: "Vaud"
99
+ vs: "Valais"
100
+ ar: "Aarau"
101
+ ```
102
+
103
+ ## Run locally
104
+ To run this module locally, we use docker-compose:
105
+ ```
106
+ docker-compose up
107
+ ```
108
+ This will run a `decidim-user_fields` container, which sleeps.
109
+ You can run any command you want in the running container, like:
110
+
111
+ - `docker-compose exec -it decidim-user_fields bundle exec rails db:seed`: seed the database (run on [`localhost:3000`](https://localhost:3000))
112
+ - `docker-compose exec -it decidim-user_fields bin/webpack-dev-server`: compile assets and watch for changes
113
+ - `docker-compose exec -it decidim-user_fields bin/rails s -b 0.0.0.0`: run rails server in development
114
+ - `docker-compose exec -it decidim-user_fields bundle exec rspec /home/decidim/module/spec`: run tests for the module
115
+ - `docker-compose exec -it decidim-user_fields bundle exec rubocop -a /home/decidim/module`: correct lint error with rubocop
116
+ - `docker-compose exec -it decidim-user_fields bash`: navigate your container in bash
117
+
118
+ While developping locally, you have two environments variables that can help you:
119
+ - `ROOT`: the root of the application using the module
120
+ - `MODULE_ROOT`: the place where your gem code is.
121
+
@@ -0,0 +1,3 @@
1
+ <!-- insert_after "erb[loud]:contains('email_field')" original "d629550ba83d41a6d1c41553b7adbed311549633" -->
2
+
3
+ <%= render partial: "/decidim/custom_user_fields/profile_form", locals: { f: f } %>
@@ -0,0 +1,5 @@
1
+ <!-- insert_bottom "h2.card-title" -->
2
+
3
+ <div class="button--title">
4
+ <%= render partial: "decidim/custom_user_fields/admin/export_users/dropdown" %>
5
+ </div>
@@ -0,0 +1,3 @@
1
+ <!-- insert_bottom "div.user-nickname" -->
2
+ <%= f.hidden_field :email %>
3
+ <%= render partial: "/decidim/custom_user_fields/registration_form", locals: { f:f, resource: resource } %>
@@ -0,0 +1,3 @@
1
+ <!-- replace "erb[loud]:contains('decidim_form_for')" -->
2
+ <% form = @form || Decidim::RegistrationForm.from_model(resource).with_context(current_organization: current_organization, current_user: current_user) %>
3
+ <%= decidim_form_for form, namespace: "invitation", as: resource_name, url: invitation_path(resource_name, invite_redirect: params[:invite_redirect]), html: { method: :put, class: "register-form new_user" } do |f| %>
@@ -0,0 +1,3 @@
1
+ <!-- insert_after "erb[loud]:contains('email_field')" -->
2
+
3
+ <%= render partial: "/decidim/custom_user_fields/registration_form", locals: { f: f, resource: resource } %>
@@ -0,0 +1,5 @@
1
+ <div class="custom-user-fields__section">
2
+ <% Decidim::CustomUserFields.custom_fields.collect do |field|
3
+ concat field.form_tag(f)
4
+ end %>
5
+ </div>
@@ -0,0 +1,5 @@
1
+ <div class="custom-user-fields__section">
2
+ <% Decidim::CustomUserFields.custom_fields.collect do |field|
3
+ concat field.form_tag(f)
4
+ end %>
5
+ </div>
@@ -0,0 +1,27 @@
1
+ module Decidim
2
+ module CustomUserFields
3
+ include ActiveSupport::Configurable
4
+
5
+ def self.configure
6
+ yield self
7
+ end
8
+
9
+ ##
10
+ # If users should receive emails on notification
11
+ # by default
12
+ config_accessor :default_email_on_notification do
13
+ false
14
+ end
15
+
16
+ def self.custom_fields
17
+ @custom_fields ||= []
18
+ end
19
+
20
+ def self.add_field(field_type, field_definition)
21
+ custom_fields.push(FieldDefinition.new(field_type, field_definition))
22
+ self
23
+ end
24
+
25
+ class Error < StandardError; end
26
+ end
27
+ end
@@ -0,0 +1,43 @@
1
+ require 'rails'
2
+ require 'decidim/core'
3
+ require 'deface'
4
+
5
+ module Decidim
6
+ module CustomUserFields
7
+ class Engine < ::Rails::Engine
8
+ isolate_namespace Decidim::CustomUserFields
9
+ routes do
10
+ # Add engine routes here
11
+ # resources :custom_user_fields
12
+ # root to: "custom_user_fields#index"
13
+ end
14
+
15
+ initializer 'decidim_custom_user_fields.registration_additions' do
16
+ config.to_prepare do
17
+ Decidim::RegistrationForm.class_eval do
18
+ include CustomUserFields::FormsDefinition
19
+ def self.require_password_on_accepting
20
+ Decidim::User.require_password_on_accepting
21
+ end
22
+ end
23
+
24
+ Decidim::OmniauthRegistrationForm.class_eval do
25
+ include CustomUserFields::FormsDefinition
26
+ end
27
+
28
+ Decidim::AccountForm.class_eval do
29
+ include CustomUserFields::FormsDefinition
30
+ end
31
+
32
+ Decidim::CreateRegistration.class_eval do
33
+ prepend CustomUserFields::Command
34
+ end
35
+
36
+ Decidim::UpdateAccount.class_eval do
37
+ prepend CustomUserFields::Command
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,34 @@
1
+ require 'forwardable'
2
+
3
+ module Decidim
4
+ module CustomUserFields
5
+ class FieldDefinition
6
+ extend Forwardable
7
+
8
+ attr_reader :type,
9
+ :name,
10
+ :field
11
+
12
+ def_delegators :@field,
13
+ :configure_form,
14
+ :map_model,
15
+ :form_tag
16
+
17
+ def initialize(name, kwargs)
18
+ @name = name.to_s.to_sym
19
+ @type = kwargs[:type]
20
+ # TODO: parse kwargs
21
+ case type
22
+ when :text
23
+ @field = Fields::TextField.new(self, kwargs)
24
+ when :textarea
25
+ @field = Fields::TextAreaField.new(self, kwargs)
26
+ when :date
27
+ @field = Fields::DateField.new(self, kwargs)
28
+ else
29
+ raise Error, "field type #{type} is not supported"
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,31 @@
1
+ module Decidim
2
+ module CustomUserFields
3
+ module Fields
4
+ class DateField < GenericField
5
+ def configure_form(form)
6
+ form.attribute(name, String)
7
+ form.validates(name, presence: required?)
8
+ end
9
+
10
+ def map_model(form, data)
11
+ form[name] = data[name] if data[name].present?
12
+ end
13
+
14
+ def form_tag(form_tag)
15
+ field_options = {}
16
+ if options[:min].present? || options[:max].present?
17
+ field_options[:min] = options[:min]
18
+ field_options[:max] = options[:max]
19
+ end
20
+
21
+ content_tag(
22
+ :div,
23
+ form_tag.date_field(name, **field_options),
24
+ class: class_name
25
+ )
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+
@@ -0,0 +1,39 @@
1
+ module Decidim
2
+ module CustomUserFields
3
+ module Fields
4
+ class GenericField
5
+ extend Forwardable
6
+ include ActionView::Helpers::TagHelper
7
+
8
+ def_delegators :@definition, :name, :type
9
+
10
+ attr_reader :definition, :options
11
+ def initialize(definition, options)
12
+ @definition = definition
13
+ @options = options
14
+ end
15
+
16
+ def configure_form(_form)
17
+ raise Error, "Configure Form is not implemented for #{definition.type} type"
18
+ end
19
+
20
+ def map_model(_form, _model_data)
21
+ raise Error, "Map Model is not implemented for #{definition.type} type"
22
+ end
23
+
24
+ def form_tag(_form)
25
+ raise Error, "Form Tag is not implemented for #{definition.type} type"
26
+ end
27
+
28
+ def class_name
29
+ class_specifier = name.to_s.underscore
30
+ "field field--#{type} field--#{class_specifier}"
31
+ end
32
+
33
+ def required?
34
+ options[:required].present? && options[:required]
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,34 @@
1
+ module Decidim
2
+ module CustomUserFields
3
+ module Fields
4
+ class TextAreaField < GenericField
5
+ def configure_form(form)
6
+ form.attribute(name, String)
7
+ form.validates(name, presence: required?)
8
+ if options[:min].present? || options[:max].present?
9
+ min_max_options = {}
10
+ min_max_options[:minimum] = options[:min].to_i
11
+ min_max_options[:maximum] = options[:max].to_i
12
+ form.validates(name, length: min_max_options, allow_blank: !required?)
13
+ end
14
+ end
15
+
16
+ def map_model(form, data)
17
+ form[name] = data[name] if data[name].present?
18
+ end
19
+
20
+ def form_tag(form_tag)
21
+ field_options = {
22
+ rows: options[:row] || 2
23
+ }
24
+ content_tag(
25
+ :div,
26
+ form_tag.text_area(name, **field_options),
27
+ class: class_name,
28
+ )
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+
@@ -0,0 +1,24 @@
1
+ module Decidim
2
+ module CustomUserFields
3
+ module Fields
4
+ class TextField < GenericField
5
+ def configure_form(form)
6
+ form.attribute(name, String)
7
+ form.validates(name, presence: required?)
8
+ end
9
+
10
+ def map_model(form, data)
11
+ form[name] = data[name] if data[name].present?
12
+ end
13
+
14
+ def form_tag(form_tag)
15
+ content_tag(
16
+ :div,
17
+ form_tag.text_field(name),
18
+ class: class_name
19
+ )
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module CustomUserFields
5
+ module ApplicationHelper
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/concern'
4
+
5
+ module Decidim
6
+ module CustomUserFields
7
+ # Changes in methods to store extra fields in user profile
8
+ module Command
9
+ extend ActiveSupport::Concern
10
+
11
+ private
12
+
13
+ def create_user
14
+ user_payload = {
15
+ email: @form.email,
16
+ name: @form.name,
17
+ nickname: @form.nickname,
18
+ password: @form.password,
19
+ password_confirmation: @form.password_confirmation,
20
+ organization: @form.current_organization,
21
+ tos_agreement: @form.tos_agreement,
22
+ newsletter_notifications_at: @form.newsletter_at,
23
+ email_on_notification: Decidim::CustomUserFields.default_email_on_notification,
24
+ accepted_tos_version: @form.current_organization.tos_version,
25
+ locale: @form.current_locale,
26
+ extended_data: extended_data
27
+ }
28
+ @user = User.create!(user_payload)
29
+ end
30
+
31
+ def update_personal_data
32
+ @user.name = @form.name
33
+ @user.nickname = @form.nickname
34
+ @user.email = @form.email
35
+ @user.personal_url = @form.personal_url
36
+ @user.about = @form.about
37
+ @user.extended_data = extended_data
38
+ end
39
+
40
+ def extended_data
41
+ custom_data = {}
42
+ Decidim::CustomUserFields.custom_fields.each do |field_def|
43
+ custom_data[field_def.name] = @form[field_def.name]
44
+ end
45
+ @extended_data ||= (@user&.extended_data || {}).merge(custom_data)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/concern'
4
+
5
+ module Decidim
6
+ module CustomUserFields
7
+ # Extra user fields definitions for forms
8
+ module FormsDefinition
9
+ extend ActiveSupport::Concern
10
+
11
+ included do |inst|
12
+ include ::Decidim::CustomUserFields::ApplicationHelper
13
+ Decidim::CustomUserFields.custom_fields.each do |field_def|
14
+ field_def.configure_form(inst)
15
+ end
16
+ end
17
+
18
+ def map_model(model)
19
+ extended_data = model.extended_data.with_indifferent_access
20
+ field_def.map_model(self, model)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,11 @@
1
+ module Decidim
2
+ module CustomUserFields
3
+ def self.version
4
+ '0.0.1'
5
+ end
6
+
7
+ def self.decidim_version
8
+ '>= 0.26'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ require 'decidim/custom_user_fields/fields/generic_field'
2
+ require 'decidim/custom_user_fields/fields/date_field'
3
+ require 'decidim/custom_user_fields/fields/text_area_field'
4
+ require 'decidim/custom_user_fields/fields/text_field'
5
+ require 'decidim/custom_user_fields/field_definition'
6
+
7
+ require 'decidim/custom_user_fields/helpers/application_helper'
8
+ require 'decidim/custom_user_fields/custom_user_fields'
9
+ require 'decidim/custom_user_fields/overrides/command'
10
+ require 'decidim/custom_user_fields/overrides/form_definition'
11
+
12
+ require 'decidim/custom_user_fields/engine'
13
+
14
+ Decidim.register_global_engine(
15
+ :decidim_custom_user_fields, # this is the name of the global method to access engine routes
16
+ ::Decidim::CustomUserFields::Engine,
17
+ at: '/decidim_custom_user_fields'
18
+ )
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: decidim-user_fields
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Hadrien Froger
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-04-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: decidim-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0.26'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0.26'
27
+ - !ruby/object:Gem::Dependency
28
+ name: deface
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.8.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.8.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: decidim-dev
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0.26'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0.26'
55
+ description: Allows to collect and manage some extra user fields on registration and
56
+ profile edition.
57
+ email:
58
+ - hadrien@octree.ch
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - README.md
64
+ - app/overrides/decidim/account/show/extra_user_fields.html.erb.deface
65
+ - app/overrides/decidim/admin/officializations/index/_export_users_dropdown.html.erb.deface
66
+ - app/overrides/decidim/devise/invitations/edit/extra_user_fields.html.erb.deface
67
+ - app/overrides/decidim/devise/invitations/edit/extra_user_fields_form.html.erb.deface
68
+ - app/overrides/decidim/devise/registrations/new/extra_user_fields.html.erb.deface
69
+ - app/views/decidim/custom_user_fields/_profile_form.html.erb
70
+ - app/views/decidim/custom_user_fields/_registration_form.html.erb
71
+ - lib/decidim/custom_user_fields/custom_user_fields.rb
72
+ - lib/decidim/custom_user_fields/engine.rb
73
+ - lib/decidim/custom_user_fields/field_definition.rb
74
+ - lib/decidim/custom_user_fields/fields/date_field.rb
75
+ - lib/decidim/custom_user_fields/fields/generic_field.rb
76
+ - lib/decidim/custom_user_fields/fields/text_area_field.rb
77
+ - lib/decidim/custom_user_fields/fields/text_field.rb
78
+ - lib/decidim/custom_user_fields/helpers/application_helper.rb
79
+ - lib/decidim/custom_user_fields/overrides/command.rb
80
+ - lib/decidim/custom_user_fields/overrides/form_definition.rb
81
+ - lib/decidim/custom_user_fields/version.rb
82
+ - lib/decidim/user_fields.rb
83
+ homepage: https://github.com/octree-gva/decidim-module-mkutano-extra_user_fields
84
+ licenses:
85
+ - AGPL-3.0
86
+ metadata: {}
87
+ post_install_message:
88
+ rdoc_options: []
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '2.7'
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements: []
102
+ rubygems_version: 3.5.3
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: Configure user fields for your decidim users
106
+ test_files: []