add submitters api
This commit is contained in:
@@ -13,6 +13,7 @@ gem 'faraday'
|
||||
gem 'google-cloud-storage', require: false
|
||||
gem 'hexapdf'
|
||||
gem 'image_processing'
|
||||
gem 'jwt'
|
||||
gem 'lograge'
|
||||
gem 'mysql2', require: false
|
||||
gem 'oj'
|
||||
|
||||
@@ -540,6 +540,7 @@ DEPENDENCIES
|
||||
google-cloud-storage
|
||||
hexapdf
|
||||
image_processing
|
||||
jwt
|
||||
letter_opener_web
|
||||
lograge
|
||||
mysql2
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
class SubmissionsController < ApiBaseController
|
||||
def create
|
||||
template = current_account.templates.find(params[:template_id])
|
||||
|
||||
submissions =
|
||||
if params[:emails].present?
|
||||
Submissions.create_from_emails(template:,
|
||||
user: current_user,
|
||||
send_email: params[:send_email] != 'false',
|
||||
emails: params[:emails])
|
||||
else
|
||||
Submissions.create_from_submitters(template:,
|
||||
user: current_user,
|
||||
send_email: params[:send_email] != 'false',
|
||||
submissions_attrs: submissions_params[:submission])
|
||||
end
|
||||
|
||||
submitters = submissions.flat_map(&:submitters)
|
||||
|
||||
if params[:send_email] != 'false'
|
||||
submitters.each do |submitter|
|
||||
SubmitterMailer.invitation_email(submitter, message: params[:message]).deliver_later!
|
||||
end
|
||||
end
|
||||
|
||||
render json: submitters
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def submissions_params
|
||||
params.permit(submission: [{ submitters: [%i[uuid name email]] }])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
module Api
|
||||
class TemplatesController < ApiBaseController
|
||||
def index
|
||||
render json: current_account.templates
|
||||
end
|
||||
|
||||
def update
|
||||
@template = current_account.templates.find(params[:id])
|
||||
|
||||
|
||||
@@ -17,9 +17,15 @@ class SubmissionsController < ApplicationController
|
||||
def create
|
||||
submissions =
|
||||
if params[:emails].present?
|
||||
create_submissions_from_emails
|
||||
Submissions.create_from_emails(template: @template,
|
||||
user: current_user,
|
||||
send_email: params[:send_email] == '1',
|
||||
emails: params[:emails])
|
||||
else
|
||||
create_submissions_from_submitters
|
||||
Submissions.create_from_submitters(template: @template,
|
||||
user: current_user,
|
||||
send_email: params[:send_email] == '1',
|
||||
submissions_attrs: submissions_params[:submission].to_h.values)
|
||||
end
|
||||
|
||||
submitters = submissions.flat_map(&:submitters)
|
||||
@@ -45,30 +51,6 @@ class SubmissionsController < ApplicationController
|
||||
|
||||
private
|
||||
|
||||
def create_submissions_from_emails
|
||||
emails = params[:emails].to_s.scan(User::EMAIL_REGEXP)
|
||||
|
||||
emails.map do |email|
|
||||
submission = @template.submissions.new(created_by_user: current_user)
|
||||
submission.submitters.new(email:, uuid: @template.submitters.first['uuid'],
|
||||
sent_at: params[:send_email] == '1' ? Time.current : nil)
|
||||
|
||||
submission.tap(&:save!)
|
||||
end
|
||||
end
|
||||
|
||||
def create_submissions_from_submitters
|
||||
submissions_params[:submission].to_h.map do |_, attrs|
|
||||
submission = @template.submissions.new(created_by_user: current_user)
|
||||
|
||||
attrs[:submitters].each do |submitter_attrs|
|
||||
submission.submitters.new(**submitter_attrs, sent_at: params[:send_email] == '1' ? Time.current : nil)
|
||||
end
|
||||
|
||||
submission.tap(&:save!)
|
||||
end
|
||||
end
|
||||
|
||||
def submissions_params
|
||||
params.permit(submission: { submitters: [%i[uuid email]] })
|
||||
end
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
class SubmitterMailer < ApplicationMailer
|
||||
DEFAULT_MESSAGE = %(You have been invited to submit the "%<name>s" form:)
|
||||
|
||||
def invitation_email(submitter, message: format(DEFAULT_MESSAGE, name: submitter.submission.template.name))
|
||||
def invitation_email(submitter, message: '')
|
||||
@submitter = submitter
|
||||
@message = message
|
||||
@message = message.presence || format(DEFAULT_MESSAGE, name: submitter.submission.template.name)
|
||||
|
||||
mail(to: @submitter.email,
|
||||
subject: 'You have been invited to submit a form',
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
# role :string not null
|
||||
# sign_in_count :integer default(0), not null
|
||||
# unlock_token :string
|
||||
# uuid :text not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# account_id :bigint not null
|
||||
@@ -32,6 +33,7 @@
|
||||
# index_users_on_email (email) UNIQUE
|
||||
# index_users_on_reset_password_token (reset_password_token) UNIQUE
|
||||
# index_users_on_unlock_token (unlock_token) UNIQUE
|
||||
# index_users_on_uuid (uuid) UNIQUE
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
@@ -49,6 +51,7 @@ class User < ApplicationRecord
|
||||
devise :registerable, :omniauthable, omniauth_providers: [:google_oauth2] if Docuseal.multitenant?
|
||||
|
||||
attribute :role, :string, default: 'admin'
|
||||
attribute :uuid, :string, default: -> { SecureRandom.uuid }
|
||||
|
||||
scope :active, -> { where(deleted_at: nil) }
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ require 'action_view/railtie'
|
||||
require 'action_mailer/railtie'
|
||||
require 'active_job/railtie'
|
||||
|
||||
require './lib/api_path_consider_json_middleware'
|
||||
|
||||
Bundler.require(*Rails.groups)
|
||||
|
||||
module DocuSeal
|
||||
@@ -26,5 +28,6 @@ module DocuSeal
|
||||
config.action_view.frozen_string_literal = true
|
||||
|
||||
config.middleware.insert_before ActionDispatch::Static, Rack::Deflater
|
||||
config.middleware.insert_before ActionDispatch::Static, ApiPathConsiderJsonMiddleware
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require './lib/auth_with_token_strategy'
|
||||
|
||||
Warden::Strategies.add(:auth_token, AuthWithTokenStrategy)
|
||||
|
||||
# Assuming you have not yet modified this file, each configuration option below
|
||||
# is set to its default value. Note that some are commented out while others
|
||||
# are not: uncommented lines are intended to protect your configuration from
|
||||
@@ -272,10 +276,10 @@ Devise.setup do |config|
|
||||
# If you want to use other strategies, that are not supported by Devise, or
|
||||
# change the failure app, you can configure them inside the config.warden block.
|
||||
#
|
||||
# config.warden do |manager|
|
||||
# manager.intercept_401 = false
|
||||
# manager.default_strategies(scope: :user).unshift :some_external_strategy
|
||||
# end
|
||||
config.warden do |manager|
|
||||
# manager.intercept_401 = false
|
||||
manager.default_strategies(scope: :user).unshift(:auth_token)
|
||||
end
|
||||
|
||||
# ==> Mountable engine configurations
|
||||
# When using Devise inside an engine, let's call it `MyEngine`, and this engine
|
||||
|
||||
+4
-2
@@ -27,9 +27,11 @@ Rails.application.routes.draw do
|
||||
end
|
||||
end
|
||||
|
||||
namespace :api do
|
||||
namespace :api, defaults: { format: :json } do
|
||||
resources :attachments, only: %i[create]
|
||||
resources :templates, only: %i[update] do
|
||||
resources :submissions, only: %i[create]
|
||||
resources :templates, only: %i[update index] do
|
||||
resources :submissions, only: %i[create]
|
||||
resources :documents, only: %i[create destroy], controller: 'templates_documents'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class AddUuidToUsers < ActiveRecord::Migration[7.0]
|
||||
class MigrationUser < ApplicationRecord
|
||||
self.table_name = 'users'
|
||||
end
|
||||
|
||||
def up
|
||||
add_column :users, :uuid, :text
|
||||
add_index :users, :uuid, unique: true
|
||||
|
||||
MigrationUser.all.each do |user|
|
||||
user.update_columns(uuid: SecureRandom.uuid)
|
||||
end
|
||||
|
||||
change_column_null :users, :uuid, false
|
||||
end
|
||||
|
||||
def down
|
||||
drop_column :users, :uuid
|
||||
end
|
||||
end
|
||||
+3
-1
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.0].define(version: 2023_07_26_062428) do
|
||||
ActiveRecord::Schema[7.0].define(version: 2023_08_03_200825) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
||||
@@ -139,10 +139,12 @@ ActiveRecord::Schema[7.0].define(version: 2023_07_26_062428) do
|
||||
t.datetime "deleted_at"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.text "uuid", null: false
|
||||
t.index ["account_id"], name: "index_users_on_account_id"
|
||||
t.index ["email"], name: "index_users_on_email", unique: true
|
||||
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
|
||||
t.index ["unlock_token"], name: "index_users_on_unlock_token", unique: true
|
||||
t.index ["uuid"], name: "index_users_on_uuid", unique: true
|
||||
end
|
||||
|
||||
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ApiPathConsiderJsonMiddleware
|
||||
def initialize(app)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
if env['PATH_INFO'].starts_with?('/api') &&
|
||||
!env['PATH_INFO'].ends_with?('/documents') &&
|
||||
!env['PATH_INFO'].ends_with?('/attachments')
|
||||
env['CONTENT_TYPE'] = 'application/json'
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,21 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class AuthWithTokenStrategy < Devise::Strategies::Base
|
||||
def valid?
|
||||
request.headers['X-Auth-Token'].present?
|
||||
end
|
||||
|
||||
def authenticate!
|
||||
payload = JsonWebToken.decode(request.headers['X-Auth-Token'])
|
||||
|
||||
user = User.find_by(uuid: payload['uuid'])
|
||||
|
||||
if user
|
||||
success!(user)
|
||||
else
|
||||
fail!('Invalid token')
|
||||
end
|
||||
rescue JWT::VerificationError
|
||||
fail!('Invalid token')
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,13 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module JsonWebToken
|
||||
module_function
|
||||
|
||||
def encode(payload)
|
||||
JWT.encode(payload, Rails.application.secrets.secret_key_base)
|
||||
end
|
||||
|
||||
def decode(token)
|
||||
JWT.decode(token, Rails.application.secrets.secret_key_base)[0]
|
||||
end
|
||||
end
|
||||
@@ -10,4 +10,33 @@ module Submissions
|
||||
|
||||
submission.save!
|
||||
end
|
||||
|
||||
def create_from_emails(template:, user:, emails:, send_email: false)
|
||||
emails = emails.to_s.scan(User::EMAIL_REGEXP)
|
||||
|
||||
emails.map do |email|
|
||||
submission = template.submissions.new(created_by_user: user)
|
||||
submission.submitters.new(email:, uuid: template.submitters.first['uuid'],
|
||||
sent_at: send_email ? Time.current : nil)
|
||||
|
||||
submission.tap(&:save!)
|
||||
end
|
||||
end
|
||||
|
||||
def create_from_submitters(template:, user:, submissions_attrs:, send_email: false)
|
||||
submissions_attrs.map do |attrs|
|
||||
submission = template.submissions.new(created_by_user: user)
|
||||
|
||||
attrs[:submitters].each_with_index do |submitter_attrs, index|
|
||||
uuid =
|
||||
submitter_attrs[:uuid].presence ||
|
||||
template.submitters.find { |e| e['name'] == submitter_attrs[:name] }&.dig('uuid') ||
|
||||
template.submitters[index]&.dig('uuid')
|
||||
|
||||
submission.submitters.new(**submitter_attrs, uuid:, sent_at: send_email ? Time.current : nil)
|
||||
end
|
||||
|
||||
submission.tap(&:save!)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user