Skip to content

Instantly share code, notes, and snippets.

@paulcsmith
Last active March 20, 2020 13:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save paulcsmith/49fc1c4c833e2e6673ba4ca934eb70f2 to your computer and use it in GitHub Desktop.
Save paulcsmith/49fc1c4c833e2e6673ba4ca934eb70f2 to your computer and use it in GitHub Desktop.
Invite user to team with Lucky
class UserInvitations::New < BrowserAction
get "/teams/:team_id/user_invitations/new" do
html NewPage, operation: InviteUser.new
end
end
class UserInvitations::Create < BrowserAction
post "/teams/:team_id/user_invitations" do
team = TeamQuery.new.team_id(team_id).find
InviteUser.create(params, invited_by: current_user.id, team_id: team.id) do |op, user_invitation|
if user_invitation
flash.success = "Yay!"
redirect Teams::Show.with(team.id)
else
flash.failure = ":("
render NewPage, operation: op
end
end
end
end
class UserInvitations::Show < BrowserAction
get "/user_invitations/:token" do
user_invitation = UserInvitationQuery.new.from_token(token).first?
if user_invitation && user.invitation.accepted
flash.info "You've already accepted this invitation, please sign in."
redirect SignIns::New
elsif user_invitation && !user_invitation.accepted?
render AcceptPage, operation: AcceptInvitation.new(user_invitation)
else
flash.failure = "This invitation does not exist or is expired"
redirect Home::Index
end
end
end
class UserInvitations::Accept < BrowserAction
post "/user_invitations/:token" do
invitation = UserInvitationQuery.new.from_token(token).first
AcceptInvitation.update(invitation, params) do |op, user|
if op.saved?
sign_in(user)
redirect Dashboard::Index
else
flash.failure "Need to make sure the form is ok"
render AcceptPage, operation: op
end
end
end
end
class UserInvitationEmail < BaseEmail
to @invitation.inviter!.email
subject "You've been invited!"
templates text, html
def initialize(@invitation : UserInvitation)
end
def email : String
@invitation.inviter!.email
end
end
# Text template example
# You've been invited to #{@invitation.team!.name}!
#
# Click here: #{UserInvitations::Show.with(token: @invitation.token}
class InviteUser < UserInvitation::SaveOperation
permit_column invitee_email
after_commit :send_invite_email
before_save do
sent_at.value = Time.utc
token.value = Random::Secure.hex(32)
end
def send_invite_email(user_invitation)
UserInvitationEmail.new(user_invitation).deliver_later
end
end
class AcceptInvitation < User::SaveOperation
attribute password : String
attribute password_confirmation : String
needs user_invitation : UserInvitation
after_save :update_invitation
def initialize
super
email.value = @user_invitation.invitee_email
end
before_save do
accepted_at.value = Time.utc
# Validate password. Probably with the password validation mixin used by SignUps
end
def update_invitation(user)
UserInvitation::SaveOperation.update!(accepted_at: Time.utc)
end
end
class UserInvitations::NewPage < MainLayout
needs operation : InviteUser
def content
form_for UserInvitations::Create do
mount Shared::Field.new(@operation.invitee_email), &.text_input(autofocus: true)
submit "Invite"
end
end
end
class UserInvitations::AcceptPage < MainLayout
needs operation : AcceptInvitation
def content
form_for UserInvitations::Accept do
mount Shared::Field.new(@operation.password)
mount Shared::Field.new(@operation.password_confirmation)
submit "Create account"
end
end
end
class UserInvitation < BaseModel
table do
column sent_at : Time
column token : String
column invitee_email : String
column accepted_at : Time?
belongs_to inviter : User
belongs_to team : Team
end
def accepted? : Bool
accepted_at.present?
end
end
class UserInvitationQuery < UserInvitation::Query
def self.from_token(token_value : String)
token(token_value).sent_at.gt(1.week.ago) # Set an expiration
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment