新增:邀请用户链接生成
This commit is contained in:
parent
42d2b51f7f
commit
c42f3d5928
|
@ -0,0 +1,36 @@
|
||||||
|
class Projects::ProjectInviteLinksController < Projects::BaseController
|
||||||
|
before_action :require_manager!, except: [:redirect_link]
|
||||||
|
before_action :require_login
|
||||||
|
|
||||||
|
def current_link
|
||||||
|
@project_invite_link = ProjectInviteLink.find_by(user_id: current_user.id, project_id: @project.id)
|
||||||
|
@project_invite_link = ProjectInviteLink.build!(@project, current_user) unless @project_invite_link.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_link
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
params_data = link_params.merge({user_id: current_user.id, project_id: @project.id})
|
||||||
|
puts params_data
|
||||||
|
Projects::ProjectInviteLinks::CreateForm.new(params_data).validate!
|
||||||
|
@project_invite_link = ProjectInviteLink.create!(params_data.merge(sign: ProjectInviteLink.random_hex_sign))
|
||||||
|
render_ok
|
||||||
|
end
|
||||||
|
rescue Exception => e
|
||||||
|
uid_logger_error(e.message)
|
||||||
|
tip_exception(e.message)
|
||||||
|
end
|
||||||
|
|
||||||
|
def redirect_link
|
||||||
|
Projects::LinkJoinService.call(current_user, @project, params[:invite_sign])
|
||||||
|
render_ok
|
||||||
|
rescue Exception => e
|
||||||
|
uid_logger_error(e.message)
|
||||||
|
tip_exception(e.message)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
def link_params
|
||||||
|
params.require(:project_invite_link).permit(:role, :is_apply)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,8 @@
|
||||||
|
class Projects::ProjectInviteLinks::CreateForm < BaseForm
|
||||||
|
attr_accessor :user_id, :project_id, :role, :is_apply
|
||||||
|
|
||||||
|
validates :user_id, :project_id, :role, presence: true
|
||||||
|
validates :role, inclusion: { in: %w(manager developer reporter), message: "请输入正确的权限." }
|
||||||
|
validates :is_apply, inclusion: {in: [true, false], message: "请输入是否需要管理员审核."}
|
||||||
|
end
|
||||||
|
|
|
@ -9,10 +9,12 @@
|
||||||
# status :integer default("0")
|
# status :integer default("0")
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
# updated_at :datetime not null
|
# updated_at :datetime not null
|
||||||
|
# project_invite_link_id :integer
|
||||||
#
|
#
|
||||||
# Indexes
|
# Indexes
|
||||||
#
|
#
|
||||||
# index_forge_applied_projects_on_project_id (project_id)
|
# index_forge_applied_projects_on_project_id (project_id)
|
||||||
|
# index_forge_applied_projects_on_project_invite_link_id (project_invite_link_id)
|
||||||
# index_forge_applied_projects_on_user_id (user_id)
|
# index_forge_applied_projects_on_user_id (user_id)
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -20,6 +22,7 @@ class AppliedProject < ApplicationRecord
|
||||||
self.table_name = "forge_applied_projects"
|
self.table_name = "forge_applied_projects"
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :project
|
belongs_to :project
|
||||||
|
belongs_to :project_invite_link, optional: true
|
||||||
|
|
||||||
has_many :applied_messages, as: :applied, dependent: :destroy
|
has_many :applied_messages, as: :applied, dependent: :destroy
|
||||||
# has_many :forge_activities, as: :forge_act, dependent: :destroy
|
# has_many :forge_activities, as: :forge_act, dependent: :destroy
|
||||||
|
|
|
@ -128,6 +128,7 @@ class Project < ApplicationRecord
|
||||||
has_many :pinned_projects, dependent: :destroy
|
has_many :pinned_projects, dependent: :destroy
|
||||||
has_many :has_pinned_users, through: :pinned_projects, source: :user
|
has_many :has_pinned_users, through: :pinned_projects, source: :user
|
||||||
has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id
|
has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id
|
||||||
|
has_many :project_invite_links, dependent: :destroy
|
||||||
after_create :incre_user_statistic, :incre_platform_statistic
|
after_create :incre_user_statistic, :incre_platform_statistic
|
||||||
after_save :check_project_members
|
after_save :check_project_members
|
||||||
before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data
|
before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: project_invite_links
|
||||||
|
#
|
||||||
|
# id :integer not null, primary key
|
||||||
|
# project_id :integer
|
||||||
|
# user_id :integer
|
||||||
|
# role :integer default("4")
|
||||||
|
# is_apply :boolean default("1")
|
||||||
|
# sign :string(255)
|
||||||
|
# expired_at :datetime
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
#
|
||||||
|
# Indexes
|
||||||
|
#
|
||||||
|
# index_project_invite_links_on_project_id (project_id)
|
||||||
|
# index_project_invite_links_on_sign (sign)
|
||||||
|
# index_project_invite_links_on_user_id (user_id)
|
||||||
|
#
|
||||||
|
|
||||||
|
class ProjectInviteLink < ApplicationRecord
|
||||||
|
|
||||||
|
default_scope { where("expired_at > ?", Time.now).or(where(expired_at: nil)) }
|
||||||
|
|
||||||
|
belongs_to :project
|
||||||
|
belongs_to :user
|
||||||
|
has_many :applied_projects
|
||||||
|
|
||||||
|
scope :with_project_id, -> (project_id) {where(project_id: project_id)}
|
||||||
|
scope :with_user_id, -> (user_id) {where(user_id: user_id)}
|
||||||
|
|
||||||
|
enum role: {manager: 3, developer: 4, reporter: 5}
|
||||||
|
|
||||||
|
before_create :set_old_data_expired_at
|
||||||
|
|
||||||
|
def self.random_hex_sign
|
||||||
|
SecureRandom.hex
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.build!(project, user, role="developer", is_apply=true)
|
||||||
|
self.create!(
|
||||||
|
project_id: project&.id,
|
||||||
|
user_id: user&.id,
|
||||||
|
role: role,
|
||||||
|
is_apply: is_apply,
|
||||||
|
sign: random_hex_sign
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def set_old_data_expired_at
|
||||||
|
ProjectInviteLink.where(user_id: self.user_id, project_id: self.project).update_all(expired_at: Time.now)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,76 @@
|
||||||
|
class Projects::LinkJoinService < ApplicationService
|
||||||
|
Error = Class.new(StandardError)
|
||||||
|
|
||||||
|
attr_reader :user, :project, :invite_sign, :params
|
||||||
|
|
||||||
|
def initialize(user, project, invite_sign, params={})
|
||||||
|
@user = user
|
||||||
|
@project = project
|
||||||
|
@invite_sign = invite_sign
|
||||||
|
@params = params
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
validate!
|
||||||
|
if invite_link.is_apply
|
||||||
|
# 如果需要申请才能加入,创建一条申请记录
|
||||||
|
create_applied_project!
|
||||||
|
else
|
||||||
|
# 如果不需要申请,直接为项目添加该成员
|
||||||
|
create_member!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def validate!
|
||||||
|
raise Error, 'invite_sign必须存在!' if invite_sign.blank?
|
||||||
|
raise Error, '邀请链接不存在!' unless invite_link.present?
|
||||||
|
raise Error, '邀请链接已失效!' unless invite_user_in_project
|
||||||
|
raise Error, '用户已加入该项目!' if project.member?(user.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_applied_project!
|
||||||
|
user.applied_projects.create!(project: project, role: role_value)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_member!
|
||||||
|
Projects::AddMemberInteractor.call(project.owner, project, user, permission)
|
||||||
|
end
|
||||||
|
|
||||||
|
def invite_link
|
||||||
|
ProjectInviteLink.find_by(project_id: project.id, sign: invite_sign)
|
||||||
|
end
|
||||||
|
|
||||||
|
def invite_user_in_project
|
||||||
|
in_project = project.member?(invite_link.user)
|
||||||
|
invite_link.update_column(:expired_at, Time.now) unless in_project
|
||||||
|
in_project
|
||||||
|
end
|
||||||
|
|
||||||
|
def role_value
|
||||||
|
@_role ||=
|
||||||
|
case invite_link&.role
|
||||||
|
when 'manager' then 3
|
||||||
|
when 'developer' then 4
|
||||||
|
when 'reporter' then 5
|
||||||
|
else
|
||||||
|
5
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def permission
|
||||||
|
case invite_link&.role
|
||||||
|
when 'manager'
|
||||||
|
'admin'
|
||||||
|
when 'developer'
|
||||||
|
'write'
|
||||||
|
when 'reporter'
|
||||||
|
'read'
|
||||||
|
else
|
||||||
|
'read'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,8 @@
|
||||||
|
json.id project.id
|
||||||
|
json.identifier project.identifier
|
||||||
|
json.name project.name
|
||||||
|
json.description project.description
|
||||||
|
json.is_public project.is_public
|
||||||
|
json.owner do
|
||||||
|
json.partial! "/users/user_simple", locals: {user: project.owner}
|
||||||
|
end
|
|
@ -0,0 +1,12 @@
|
||||||
|
json.(project_invite_link, :id, :role, :is_apply, :sign)
|
||||||
|
|
||||||
|
json.user do
|
||||||
|
json.partial! "/users/user_simple", locals: {user: project_invite_link.user}
|
||||||
|
end
|
||||||
|
if project_invite_link&.project.present?
|
||||||
|
json.project do
|
||||||
|
json.partial! "/projects/detail", locals: {project: project_invite_link.project}
|
||||||
|
end
|
||||||
|
else
|
||||||
|
json.project nil
|
||||||
|
end
|
|
@ -0,0 +1 @@
|
||||||
|
json.partial! 'detail', locals: { project_invite_link: @project_invite_link }
|
|
@ -603,6 +603,13 @@ Rails.application.routes.draw do
|
||||||
post :cancel
|
post :cancel
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
resources :project_invite_links, only: [:index] do
|
||||||
|
collection do
|
||||||
|
get :current_link
|
||||||
|
post :generate_link
|
||||||
|
post :redirect_link
|
||||||
|
end
|
||||||
|
end
|
||||||
resources :webhooks, except: [:show, :new] do
|
resources :webhooks, except: [:show, :new] do
|
||||||
member do
|
member do
|
||||||
get :tasks
|
get :tasks
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
class CreateProjectInviteLinks < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
create_table :project_invite_links do |t|
|
||||||
|
t.references :project
|
||||||
|
t.references :user
|
||||||
|
t.integer :role, default: 4
|
||||||
|
t.boolean :is_apply, default: true
|
||||||
|
t.string :sign
|
||||||
|
t.datetime :expired_at
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :project_invite_links, :sign
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,6 @@
|
||||||
|
class AddProjectInviteLinkToAppliedProjects < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
add_column :forge_applied_projects, :project_invite_link_id, :integer
|
||||||
|
add_index :forge_applied_projects, :project_invite_link_id
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe ProjectInviteLink, type: :model do
|
||||||
|
pending "add some examples to (or delete) #{__FILE__}"
|
||||||
|
end
|
Loading…
Reference in New Issue