2023-12-04 23:55:01 +00:00
/ *
2023-12-05 09:24:03 +00:00
* owobot - Your server ' s guardian and entertainer
2023-12-04 23:55:01 +00:00
* Copyright ( C ) 2023 owobot Contributors
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Affero General Public License for more details .
*
* You should have received a copy of the GNU Affero General Public License
* along with this program . If not , see < https : //www.gnu.org/licenses/>.
* /
package vetting
import (
"database/sql"
"errors"
"fmt"
"slices"
"strings"
"github.com/bwmarrin/discordgo"
"go.elara.ws/logger/log"
"go.elara.ws/owobot/internal/cache"
"go.elara.ws/owobot/internal/db"
"go.elara.ws/owobot/internal/systems/eventlog"
"go.elara.ws/owobot/internal/systems/tickets"
"go.elara.ws/owobot/internal/util"
)
// onMemberJoin adds the vetting role to a user when they join in order to allow them
// to access the vetting questions
func onMemberJoin ( s * discordgo . Session , gma * discordgo . GuildMemberAdd ) {
guild , err := db . GuildByID ( gma . GuildID )
if err != nil {
log . Warn ( "Error getting guild from database" ) . Str ( "guild-id" , gma . GuildID ) . Str ( "task" , "vetting-member-join" ) . Err ( err ) . Send ( )
return
}
2023-12-06 01:36:03 +00:00
if guild . VettingRoleID == "" || guild . VettingReqChanID == "" {
err = welcomeUser ( s , guild , gma . Member . User )
if err != nil {
log . Warn ( "Error welcoming user" ) . Err ( err )
}
2023-12-04 23:55:01 +00:00
return
}
err = s . GuildMemberRoleAdd ( gma . GuildID , gma . User . ID , guild . VettingRoleID )
if err != nil {
log . Warn ( "Error assigning vetting role to new user" ) . Str ( "guild-id" , gma . GuildID ) . Str ( "task" , "vetting-member-join" ) . Err ( err ) . Send ( )
return
}
}
// onMakeVettingMsg deletes and reposts a message with a vetting request button
// that allows users to request vetting.
func onMakeVettingMsg ( s * discordgo . Session , i * discordgo . InteractionCreate ) error {
data := i . ApplicationCommandData ( )
msg := data . Resolved . Messages [ data . TargetID ]
err := s . InteractionRespond ( i . Interaction , & discordgo . InteractionResponse {
Type : discordgo . InteractionResponseChannelMessageWithSource ,
Data : & discordgo . InteractionResponseData {
Content : msg . Content ,
Components : [ ] discordgo . MessageComponent {
discordgo . ActionsRow { Components : [ ] discordgo . MessageComponent {
discordgo . Button {
Label : "Request Vetting" ,
Style : discordgo . SuccessButton ,
Disabled : false ,
2024-01-10 08:14:27 +00:00
Emoji : & discordgo . ComponentEmoji { Name : clipboardEmoji } ,
2023-12-04 23:55:01 +00:00
CustomID : "vetting-req" ,
} ,
} } ,
} ,
} ,
} )
if err != nil {
return err
}
return s . ChannelMessageDelete ( msg . ChannelID , msg . ID )
}
// onVettingRequest handles sends vetting requests in the vetting request channel
func onVettingRequest ( s * discordgo . Session , i * discordgo . InteractionCreate ) error {
if i . Type != discordgo . InteractionMessageComponent {
return nil
}
data := i . MessageComponentData ( )
if data . CustomID != "vetting-req" {
return nil
}
2023-12-06 01:12:05 +00:00
_ , err := db . VettingReqMsgID ( i . GuildID , i . Member . User . ID )
if err == nil {
return errors . New ( "you've already sent a vetting request" )
}
2023-12-04 23:55:01 +00:00
guild , err := db . GuildByID ( i . GuildID )
if err != nil {
return err
}
if guild . VettingRoleID == "" || guild . VettingReqChanID == "" {
return nil
}
if ! slices . Contains ( i . Member . Roles , guild . VettingRoleID ) {
return errors . New ( "you do not have the vetting role" )
}
2023-12-05 21:28:47 +00:00
embed := & discordgo . MessageEmbed {
Title : "Vetting Request" ,
Author : & discordgo . MessageEmbedAuthor {
Name : i . Member . User . Username ,
IconURL : i . Member . User . AvatarURL ( "" ) ,
2023-12-04 23:55:01 +00:00
} ,
2023-12-05 21:28:47 +00:00
Description : "Accept the vetting request to create a ticket, or reject it to kick the user." ,
}
eventlog . AddTimeToEmbed ( guild . TimeFormat , embed )
2023-12-06 01:12:05 +00:00
msg , err := s . ChannelMessageSendComplex ( guild . VettingReqChanID , & discordgo . MessageSend {
2023-12-05 21:28:47 +00:00
Embeds : [ ] * discordgo . MessageEmbed { embed } ,
2023-12-04 23:55:01 +00:00
Components : [ ] discordgo . MessageComponent {
discordgo . ActionsRow { Components : [ ] discordgo . MessageComponent {
discordgo . Button {
Label : "Accept" ,
2024-01-10 08:14:27 +00:00
Emoji : & discordgo . ComponentEmoji { Name : checkEmoji } ,
2023-12-04 23:55:01 +00:00
Style : discordgo . SuccessButton ,
CustomID : "vetting-accept:" + i . Member . User . ID ,
} ,
discordgo . Button {
Label : "Reject" ,
2024-01-10 08:14:27 +00:00
Emoji : & discordgo . ComponentEmoji { Name : crossEmoji } ,
2023-12-04 23:55:01 +00:00
Style : discordgo . DangerButton ,
CustomID : "vetting-reject:" + i . Member . User . ID ,
} ,
} } ,
} ,
} )
if err != nil {
return err
}
2023-12-06 01:12:05 +00:00
err = db . AddVettingReq ( i . GuildID , i . Member . User . ID , msg . ID )
if err != nil {
return err
}
2023-12-04 23:55:01 +00:00
return util . RespondEphemeral ( s , i . Interaction , "Successfully sent your vetting request!" )
}
// onVettingResponse handles responses to vetting requests. If the user was accepted,
// it creates a vetting ticket for them. If they were rejected, it kicks them from the server.
func onVettingResponse ( s * discordgo . Session , i * discordgo . InteractionCreate ) error {
if i . Type != discordgo . InteractionMessageComponent {
return nil
}
data := i . MessageComponentData ( )
resType , userID , ok := strings . Cut ( data . CustomID , ":" )
if ! ok {
return nil
}
if resType != "vetting-accept" && resType != "vetting-reject" {
return nil
}
2023-12-05 21:28:47 +00:00
guild , err := db . GuildByID ( i . GuildID )
if err != nil {
return err
}
2023-12-04 23:55:01 +00:00
executor := i . Member
member , err := cache . Member ( s , i . GuildID , userID )
if err != nil {
return err
}
switch resType {
case "vetting-accept" :
channelID , err := tickets . Open ( s , i . GuildID , member . User , executor . User )
if err != nil {
return err
}
2023-12-05 21:28:47 +00:00
embed := & discordgo . MessageEmbed {
Title : "Vetting Request Accepted!" ,
Description : fmt . Sprintf ( "This vetting request has been accepted and a vetting ticket has been created at <#%s>.\n\n**Accepted By:** <@%s>" , channelID , executor . User . ID ) ,
Author : & discordgo . MessageEmbedAuthor {
Name : member . User . Username ,
IconURL : member . User . AvatarURL ( "" ) ,
} ,
}
eventlog . AddTimeToEmbed ( guild . TimeFormat , embed )
2023-12-04 23:55:01 +00:00
err = s . InteractionRespond ( i . Interaction , & discordgo . InteractionResponse {
Type : discordgo . InteractionResponseUpdateMessage ,
Data : & discordgo . InteractionResponseData {
2023-12-05 21:28:47 +00:00
Embeds : [ ] * discordgo . MessageEmbed { embed } ,
2023-12-04 23:55:01 +00:00
} ,
} )
if err != nil {
return err
}
case "vetting-reject" :
err = s . GuildMemberDeleteWithReason ( i . GuildID , member . User . ID , "Vetting request rejected" )
if err != nil {
return err
}
2023-12-05 21:28:47 +00:00
embed := & discordgo . MessageEmbed {
Title : "Vetting Request Rejected" ,
Description : fmt . Sprintf ( "This vetting request has been rejected and <@%s> has been kicked from the server.\n\n**Rejected By:** <@%s>" , member . User . ID , executor . User . ID ) ,
Author : & discordgo . MessageEmbedAuthor {
Name : member . User . Username ,
IconURL : member . User . AvatarURL ( "" ) ,
} ,
}
eventlog . AddTimeToEmbed ( guild . TimeFormat , embed )
2023-12-04 23:55:01 +00:00
err = s . InteractionRespond ( i . Interaction , & discordgo . InteractionResponse {
Type : discordgo . InteractionResponseUpdateMessage ,
Data : & discordgo . InteractionResponseData {
2023-12-05 21:28:47 +00:00
Embeds : [ ] * discordgo . MessageEmbed { embed } ,
2023-12-04 23:55:01 +00:00
} ,
} )
if err != nil {
return err
}
}
2023-12-06 01:12:05 +00:00
2023-12-12 20:50:26 +00:00
return nil
2023-12-04 23:55:01 +00:00
}
2023-12-08 16:11:17 +00:00
2023-12-31 22:41:08 +00:00
// onMemberLeave handles users leaving the server. It closes any tickets they might've had open.
2023-12-08 16:11:17 +00:00
func onMemberLeave ( s * discordgo . Session , gmr * discordgo . GuildMemberRemove ) {
msgID , err := db . VettingReqMsgID ( gmr . GuildID , gmr . Member . User . ID )
if errors . Is ( err , sql . ErrNoRows ) {
return
} else if err != nil {
log . Error ( "Error getting vetting request ID after member leave" ) . Str ( "user-id" , gmr . Member . User . ID ) . Err ( err ) . Send ( )
return
}
guild , err := db . GuildByID ( gmr . GuildID )
if err != nil {
log . Error ( "Error getting guild" ) . Str ( "guild-id" , gmr . GuildID ) . Err ( err ) . Send ( )
return
}
if guild . VettingReqChanID != "" {
err = s . ChannelMessageDelete ( guild . VettingReqChanID , msgID )
if err != nil {
log . Error ( "Error deleting vetting request message after member leave" ) . Str ( "msg-id" , msgID ) . Err ( err ) . Send ( )
}
}
2024-01-22 23:44:11 +00:00
err = db . RemoveVettingReq ( gmr . GuildID , gmr . Member . User . ID )
2023-12-08 16:11:17 +00:00
if err != nil {
log . Error ( "Error removing vetting request after member leave" ) . Str ( "user-id" , gmr . Member . User . ID ) . Err ( err ) . Send ( )
}
}