class editCharacterTraitAdd(APIResponse): def __init__(self): super(editCharacterTraitAdd, self).__init__(config, session, min_access_level=2, accepted_input = { 'traitId': (MUST, validator_str_range(1, 20)), # I'm validating the trait later because I also need trait data 'charId': (MUST, validator_character), }) @web_security(sec.OR(sec.IsAdmin, sec.AND( sec.IsUser, sec.genCanEditCharacter(target_character = 'charId')))) def mGET(self): lid = getLanguage(self.session, dbm) issuer = self.session.discord_userid character = self.input_data['charId'] trait_id = self.input_data['traitId'] charId = character['id'] try: _ = dbm.getTrait(charId, trait_id) raise WebException("The character already has this trait", 400) except ghostDB.DBException as e: pass trait = dbm.validators.getValidateTrait(trait_id).get() if trait['textbased']: textval = "" dbm.db.insert("CharacterTrait", trait=trait_id, playerchar=charId, cur_value = 0, max_value = 0, text_value = textval, pimp_max = 0) dbm.log(issuer, character['id'], trait['id'], ghostDB.LogType.TEXT_VALUE, textval, '', "web edit") else: numval = 0 pimp = 6 if trait['traittype'] in ['fisico', 'sociale', 'mentale'] else 0 dbm.db.insert("CharacterTrait", trait=trait_id, playerchar=charId, cur_value = numval, max_value = numval, text_value = "", pimp_max = pimp) dbm.log(issuer, character['id'], trait['id'], ghostDB.LogType.MAX_VALUE, numval, '', "web edit") return dbm.getTrait_LangSafe(charId, trait_id, lid)
class editCharacterTraitNumberCurrent(APIResponse): # no textbased def __init__(self): super(editCharacterTraitNumberCurrent, self).__init__(config, session, min_access_level=2, accepted_input = { 'traitId': (MUST, validator_trait_number), 'charId': (MUST, validator_character), 'newValue': (MUST, validator_positive_integer), }) @web_security(sec.OR(sec.IsAdmin, sec.AND( sec.IsUser, sec.genCanEditCharacter(target_character = 'charId')))) def mGET(self): lid = getLanguage(self.session, dbm) issuer = self.session.discord_userid character = self.input_data['charId'] trait_id = self.input_data['traitId'] new_val = self.input_data['newValue'] charId = character['id'] trait = dbm.getTrait(charId, trait_id) if trait['pimp_max']==0 and trait['trackertype']==0: raise WebException(f"Current value cannot be modified") if new_val > trait['max_value'] and trait['trackertype'] != 3: raise WebException("Value too large", 400) dbm.db.update("CharacterTrait", where='trait = $trait and playerchar = $pc', vars=dict(trait=trait_id, pc=character['id']), cur_value = new_val) dbm.log(issuer, character['id'], trait_id, ghostDB.LogType.CUR_VALUE, new_val, trait['cur_value'], "web edit") return dbm.getTrait_LangSafe(charId, trait_id, lid)
def mGET(self): query = """ select p.userid as value, p.name as display from People p """ # only storytellers and admins can see the list of registered users, but we can still reassign if we know the discordid (as you would on the bot) cansee = check_web_security(self, sec.OR(sec.IsAdmin, sec.IsStoryteller)) data = [] if cansee: data = dbm.db.query(query, vars=dict(langId=getLanguage(session, dbm))).list() return data
class editTranslations(WebPageResponseLang): def __init__(self): super(editTranslations, self).__init__(config, session) @web_security(sec.OR(sec.IsAdmin, sec.IsStoryteller)) def mGET(self): query = """ select tt.id, lt.langId, lt.traitShort, lt.traitName from Trait tt join LangTrait lt on (lt.traitId = tt.id and lt.langId = $langId) order by tt.standard desc, tt.traittype asc, tt.ordering asc """ traitData = dbm.db.query(query, vars=dict(langId=self.getLangId())) return render.translationEdit(global_template_params, self.getLanguageDict(), f'{self.session.discord_username}#{self.session.discord_userdiscriminator}', self.getString("web_label_logout"), "doLogout", traitData)
class editCharacterReassign(APIResponse): #textbased def __init__(self): super(editCharacterReassign, self).__init__(config, session, min_access_level=2, accepted_input = { 'userId': (MUST, validator_bot_user), 'charId': (MUST, validator_character), }) @web_security(sec.OR(sec.IsAdmin, sec.AND( sec.IsUser, sec.genCanEditCharacter(target_character = 'charId')))) def mGET(self): character = self.input_data['charId'] charId = character['id'] user = self.input_data['userId'] userId = user['userid'] dbm.reassignCharacter(charId, userId) return user
class editCharacterTraitText(APIResponse): #textbased def __init__(self): super(editCharacterTraitText, self).__init__(config, session, min_access_level=2, accepted_input = { 'traitId': (MUST, validator_trait_textbased), 'charId': (MUST, validator_character), 'newValue': (MUST, validator_str_range(1, 50)), }) @web_security(sec.OR(sec.IsAdmin, sec.AND( sec.IsUser, sec.genCanEditCharacter(target_character = 'charId')))) def mGET(self): issuer = self.session.discord_userid character = self.input_data['charId'] trait_id = self.input_data['traitId'] new_val = self.input_data['newValue'] charId = character['id'] trait = dbm.getTrait(charId, trait_id) dbm.db.update("CharacterTrait", where='trait = $trait and playerchar = $pc', vars=dict(trait=trait_id, pc=character['id']), text_value = new_val) dbm.log(issuer, character['id'], trait_id, ghostDB.LogType.TEXT_VALUE, new_val, trait['text_value'], "web edit") return dbm.getTrait_LangSafe(charId, trait_id, getLanguage(self.session, dbm))
class editCharacterTraitRemove(APIResponse): #textbased def __init__(self): super(editCharacterTraitRemove, self).__init__(config, session, min_access_level=2, accepted_input = { 'traitId': (MUST, validator_trait), 'charId': (MUST, validator_character), }) @web_security(sec.OR(sec.IsAdmin, sec.AND( sec.IsUser, sec.genCanEditCharacter(target_character = 'charId')))) def mGET(self): issuer = self.session.discord_userid character = self.input_data['charId'] trait_id = self.input_data['traitId'] charId = character['id'] trait = dbm.getTrait(charId, trait_id) updated_rows = dbm.db.delete("CharacterTrait", where='trait = $trait and playerchar = $pc', vars=dict(trait=trait['id'], pc=character['id'])) if trait['textbased']: dbm.log(issuer, character['id'], trait['id'], ghostDB.LogType.DELETE, "", trait['text_value'], "web edit") else: dbm.log(issuer, character['id'], trait['id'], ghostDB.LogType.DELETE, "", f"{trait['cur_value']}/{trait['max_value']}", "web edit") return {"trait": trait_id}
class editTranslation(APIResponse): def __init__(self): super(editTranslation, self).__init__(config, session, accepted_input = { 'traitId': (MUST, validator_trait), 'type': (MUST, validator_set( ("short", "name") )), 'langId': (MUST, validator_language), 'value': (MUST, validator_str_range(1, 50)), }) @web_security(sec.OR(sec.IsAdmin, sec.IsStoryteller)) def mGET(self): u = 0 if self.input_data['type'] == "short": u = dbm.db.update("LangTrait", where = 'traitId = $traitId and langId = $langId', vars = dict(traitId=self.input_data['traitId'], langId = self.input_data['langId']), traitShort = self.input_data['value']) elif self.input_data['type'] == "name": u = dbm.db.update("LangTrait", where = 'traitId = $traitId and langId = $langId', vars = dict(traitId=self.input_data['traitId'], langId = self.input_data['langId']), traitName = self.input_data['value']) else: # does not ever happen raise WebException("Invalid input", 400) if u == 1: return self.input_data else: raise WebException(f"Something went wrong: {u} rows affected", 500)
class GreedyGhostCog_PCMod(gb.GreedyGhostCog): @commands.group(brief='Gestione personaggi') @commands.before_invoke(gs.command_security(gs.basicRegisteredUser)) async def pgmod(self, ctx: commands.Context): if ctx.invoked_subcommand is None: response = utils.discord_text_format_mono('Azioni disponibili:\n\n' + '\n'.join(list(map(lambda k: f'{k} - {pgmod_help[k][1]}', pgmod_help)))) await self.bot.atSend(ctx, response) @pgmod.command(name = 'create', brief = "Crea un personaggio", description = create_description) @commands.before_invoke(gs.command_security(sec.OR(sec.IsAdmin, sec.AND( sec.OR(sec.IsActiveOnGuild, sec.IsPrivateChannelWithRegisteredUser), sec.OR(sec.IsStoryteller, sec.genIsSelf(optional_target_user = 3)))))) async def create(self, ctx : commands.Context, character_id: gc.GreedyShortIdConverter, user: gc.RegisteredUserConverter, name, *args): fullname = " ".join(list([name]+list(args))) self.bot.dbm.newCharacter(character_id, fullname, user['userid']) await self.bot.atSend(ctx, f'Il personaggio {fullname} è stato inserito!') @pgmod.command(name = 'link', brief = "Aggiunge un personaggio ad una cronaca", description = link_description) @commands.before_invoke(gs.command_security(sec.OR(sec.IsAdmin, sec.AND( sec.OR(sec.IsActiveOnGuild, sec.IsPrivateChannelWithRegisteredUser), sec.genIsChronicleStoryteller(target_chronicle = 3))))) async def link(self, ctx: commands.Context, character: gc.CharacterConverter, chronicle: gc.ChronicleConverter): is_linked, _ = self.bot.dbm.isCharacterLinkedToChronicle(character['id'], chronicle['id']) if is_linked: await self.bot.atSend(ctx, f"C'è già un'associazione tra {character['fullname']} e {chronicle['name']}") else: self.bot.dbm.db.insert("ChronicleCharacterRel", chronicle=chronicle['id'], playerchar=character['id']) await self.bot.atSend(ctx, f"{character['fullname']} ora gioca a {chronicle['name']}") @pgmod.command(name = 'unlink', brief = "Disassocia un personaggio da una cronaca", description = unlink_description) @commands.before_invoke(gs.command_security(sec.OR(sec.IsAdmin, sec.AND( sec.OR(sec.IsActiveOnGuild, sec.IsPrivateChannelWithRegisteredUser), sec.genIsChronicleStoryteller(target_chronicle = 3))))) async def unlink(self, ctx: commands.Context, character: gc.CharacterConverter, chronicle: gc.ChronicleConverter): is_linked, _ = self.bot.dbm.isCharacterLinkedToChronicle(character['id'], chronicle['id']) if is_linked: self.bot.dbm.db.delete("ChronicleCharacterRel", where = 'playerchar=$playerchar and chronicle=$chronicleid', vars=dict(chronicleid=chronicle['id'], playerchar=character['id'])) await self.bot.atSend(ctx, f"{character['fullname']} ora non gioca più a {chronicle['name']}") else: await self.bot.atSend(ctx, f"Non c\'è un\'associazione tra {character['fullname']} e {chronicle['name']}") @pgmod.command(name = 'addt', brief = "Aggiunge tratto ad un personaggio", description = addt_description) @commands.before_invoke(gs.command_security(sec.OR(sec.IsAdmin, sec.AND( sec.OR(sec.IsActiveOnGuild, sec.IsPrivateChannelWithRegisteredUser), sec.genCanEditCharacter(target_character=2))))) async def addt(self, ctx: gb.GreedyContext, character: gc.CharacterConverter, trait: gc.TraitConverter, value, *args): issuer = str(ctx.message.author.id) try: lid = ctx.getLID() ptrait = self.bot.dbm.getTrait_LangSafe(character['id'], trait['id'], lid) raise gb.BotException(f"{character['fullname']} ha già il tratto {ptrait['name']} ") except ghostDB.DBException: pass ttype = self.bot.dbm.db.select('TraitType', where='id=$id', vars=dict(id=trait['traittype']))[0] val = None if ttype['textbased']: val = " ".join([value]+list(args)) self.bot.dbm.db.insert("CharacterTrait", trait=trait['id'], playerchar=character['id'], cur_value = 0, max_value = 0, text_value = val, pimp_max = 0) self.bot.dbm.log(issuer, character['id'], trait['id'], ghostDB.LogType.TEXT_VALUE, val, '', ctx.message.content) else: val = int(value) pimp = 6 if trait['traittype'] in ['fisico', 'sociale', 'mentale'] else 0 self.bot.dbm.db.insert("CharacterTrait", trait=trait['id'], playerchar=character['id'], cur_value = val, max_value = val, text_value = "", pimp_max = pimp) self.bot.dbm.log(issuer, character['id'], trait['id'], ghostDB.LogType.MAX_VALUE, val, '', ctx.message.content) await self.bot.atSend(ctx, f"{character['fullname']} ora ha {trait['name']} {val}") @pgmod.command(name = 'modt', brief = "Modifica un tratto di un personaggio", description = modt_description) @commands.before_invoke(gs.command_security(sec.OR(sec.IsAdmin, sec.AND( sec.OR(sec.IsActiveOnGuild, sec.IsPrivateChannelWithRegisteredUser), sec.genCanEditCharacter(target_character = 2))))) async def modt(self, ctx: gb.GreedyContext, character: gc.CharacterConverter, trait: gc.TraitConverter, value, *args): issuer = str(ctx.message.author.id) chartrait = self.bot.dbm.getTrait_LangSafe(character['id'], trait['id'], ctx.getLID()) ttype = self.bot.dbm.db.select('TraitType', where='id=$id', vars=dict(id=trait['traittype']))[0] val = None if ttype['textbased']: val = " ".join([value]+list(args)) self.bot.dbm.db.update("CharacterTrait", where='trait = $trait and playerchar = $pc', vars=dict(trait=trait['id'], pc=character['id']), text_value = val) self.bot.dbm.log(issuer, character['id'], trait['id'], ghostDB.LogType.TEXT_VALUE, val, chartrait['text_value'], ctx.message.content) else: val = int(value) self.bot.dbm.db.update("CharacterTrait", where='trait = $trait and playerchar = $pc', vars=dict(trait=trait['id'], pc=character['id']), cur_value = val, max_value = val) self.bot.dbm.log(issuer, character['id'], trait['id'], ghostDB.LogType.MAX_VALUE, val, chartrait['max_value'], ctx.message.content) self.bot.dbm.log(issuer, character['id'], trait['id'], ghostDB.LogType.CUR_VALUE, val, chartrait['cur_value'], ctx.message.content) await self.bot.atSend(ctx, f"{character['fullname']} ora ha {trait['name']} {val}") @pgmod.command(name = 'rmt', brief = "Rimuovi un tratto ad un personaggio", description = rmt_description) @commands.before_invoke(gs.command_security(sec.OR(sec.IsAdmin, sec.AND( sec.OR(sec.IsActiveOnGuild, sec.IsPrivateChannelWithRegisteredUser), sec.genCanEditCharacter(target_character = 2))))) async def rmt(self, ctx: gb.GreedyContext, character: gc.CharacterConverter, trait: gc.TraitConverter): issuer = str(ctx.message.author.id) chartrait = self.bot.dbm.getTrait_LangSafe(character['id'], trait['id'], ctx.getLID()) ttype = self.bot.dbm.db.select('TraitType', where='id=$id', vars=dict(id=trait['traittype']))[0] updated_rows = self.bot.dbm.db.delete("CharacterTrait", where='trait = $trait and playerchar = $pc', vars=dict(trait=trait['id'], pc=character['id'])) if ttype['textbased']: self.bot.dbm.log(issuer, character['id'], trait['id'], ghostDB.LogType.DELETE, "", chartrait['text_value'], ctx.message.content) else: self.bot.dbm.log(issuer, character['id'], trait['id'], ghostDB.LogType.DELETE, "", f"{chartrait['cur_value']}/{chartrait['max_value']}", ctx.message.content) if updated_rows > 0: await self.bot.atSend(ctx, f"Rimosso {trait['name']} da {character['fullname']} ({updated_rows})") else: await self.bot.atSend(ctx, f"Nessun tratto rimosso") @pgmod.command(name = 'reassign', brief = pgmod_help["reassign"][1], description = pgmod_help["reassign"][0]) @commands.before_invoke(gs.command_security(sec.OR(sec.IsAdmin, sec.AND( sec.OR(sec.IsActiveOnGuild, sec.IsPrivateChannelWithRegisteredUser), sec.genCanEditCharacter(target_character = 2))))) async def reassign(self, ctx: commands.Context, character: gc.CharacterConverter, user: gc.RegisteredUserConverter): self.bot.dbm.reassignCharacter(character['id'], user['userid']) await self.bot.atSendLang(ctx, "string_msg_character_reassigned_to_user", character["fullname"], user['name'])
class GreedyGhostCog_Session(gb.GreedyGhostCog): @commands.group( name='session', brief='Controlla le sessioni di gioco', description= "Le sessioni sono basate sui canali: un canale può ospitare una sessione alla volta, ma la stessa cronaca può avere sessioni attive in più canali." ) @commands.before_invoke(gs.command_security(gs.basicStoryTeller)) async def session(self, ctx: commands.Context): if ctx.invoked_subcommand is None: sessions = self.bot.dbm.db.select( 'GameSession', where='channel=$channel', vars=dict(channel=ctx.channel.id)) if len(sessions): chronicle = self.bot.dbm.db.select( 'Chronicle', where='id=$chronicle', vars=dict(chronicle=sessions[0]['chronicle'])) cn = chronicle[0]['name'] await self.bot.atSend(ctx, f"Sessione attiva: {cn}") else: await self.bot.atSend( ctx, "Nessuna sessione attiva in questo canale!") @session.command( name='start', brief='Inizia una sessione', description= '.session start <nomecronaca>: inizia una sessione per <nomecronaca> (richiede essere admin o storyteller della cronaca da iniziare) (richiede essere admin o storyteller della cronaca da iniziare)' ) @commands.before_invoke( gs.command_security( sec.OR( sec.IsAdmin, sec.AND( sec.OR(sec.IsActiveOnGuild, sec.IsPrivateChannelWithRegisteredUser), sec.genIsChronicleStoryteller(target_chronicle=2))))) async def start(self, ctx: commands.Context, chronicle: gc.ChronicleConverter): chronicleid = chronicle['id'].lower() response = '' sessions = self.bot.dbm.db.select('GameSession', where='channel=$channel', vars=dict(channel=ctx.channel.id)) if len(sessions): response = f"C'è già una sessione in corso in questo canale: {sessions[0]['chronicle']}" else: self.bot.dbm.db.insert('GameSession', chronicle=chronicleid, channel=ctx.channel.id) response = f"Sessione iniziata per la cronaca {chronicle['name']}" # TODO lista dei pg? # TODO notifica i giocatori di pimp attivi await self.bot.atSend(ctx, response) @session.command( name='list', brief='Elenca le sessioni aperte', description= 'Elenca le sessioni aperte. richiede di essere admin o storyteller') @commands.before_invoke(gs.command_security(gs.basicStoryTeller)) async def session_list(self, ctx: commands.Context): sessions = self.bot.dbm.db.select('GameSession').list() channels = [] lines = [] for s in sessions: try: ch = await self.bot.fetch_channel(int(s['channel'])) channels.append(ch) except discord.errors.Forbidden as e: lines.append(f"**{s['chronicle']}** in: UNKNOWN") channels.append(None) #pvt = 0 for session, channel in zip(sessions, channels): if isinstance(channel, discord.abc.GuildChannel): lines.append( f"**{session['chronicle']}** in: {channel.guild.name}/{channel.category}/{channel.name}" ) elif isinstance(channel, discord.abc.PrivateChannel): lines.append( f"**{session['chronicle']}** in un canale privato") if not len(lines): lines.append("Nessuna!") response = "Sessioni attive:\n" + ("\n".join(lines)) await self.bot.atSend(ctx, response) @session.command( name='end', brief='Termina la sessione corrente', description= 'Termina la sessione corrente. Richiede di essere admin o storyteller della sessione in corso.' ) @commands.before_invoke( gs.command_security( sec.OR( sec.IsAdmin, sec.AND( sec.OR(sec.IsActiveOnGuild, sec.IsPrivateChannelWithRegisteredUser), sec.CanEditRunningSession)))) async def end(self, ctx: commands.Context): response = '' n = self.bot.dbm.db.delete('GameSession', where='channel=$channel', vars=dict(channel=ctx.channel.id)) if n: response = f'sessione terminata' else: # non dovrebbe mai accadere response = f'Non c\'è una sessione aperta in questo canale' await self.bot.atSend(ctx, response)
class GreedyGhostCog_GMadm(gb.GreedyGhostCog): @commands.group(brief='Gestione sistema di gioco') @commands.before_invoke(gs.command_security(gs.basicStoryTeller)) async def gmadm(self, ctx: commands.Context): if ctx.invoked_subcommand is None: response = utils.discord_text_format_mono('Azioni disponibili:\n\n' + '\n'.join(list(map(lambda k: f'{k} - {gmadm_help[k][1]}', gmadm_help)))) await self.bot.atSend(ctx, response) @gmadm.command(name = 'listChronicles', brief = gmadm_help['listChronicles'][1], description = listChronicles_description) @commands.before_invoke(gs.command_security(gs.basicStoryTeller)) async def listChronicles(self, ctx: commands.Context): query = """ SELECT cr.id as cid, cr.name as cname, p.name as pname FROM Chronicle cr JOIN StoryTellerChronicleRel stcr on (cr.id = stcr.chronicle) JOIN People p on (stcr.storyteller = p.userid) """ results = self.bot.dbm.db.query(query) if len(results) == 0: await self.bot.atSend(ctx, "Nessuna cronaca trovata!") return chronicles = {} crst = {} for c in results: chronicles[c['cid']] = c['cname'] if not c['cid'] in crst: crst[c['cid']] = [] crst[c['cid']].append(c['pname']) await self.bot.atSend(ctx, "Cronache:\n" + "\n".join(list(map(lambda x: f"**{chronicles[x]}** ({x}) (storyteller: {', '.join(crst[x])})", chronicles)))) @gmadm.command(name = 'newChronicle', brief = gmadm_help['newChronicle'][1], description = newChronicle_description) @commands.before_invoke(gs.command_security(gs.basicStoryTeller)) async def newChronicle(self, ctx: commands.Context, shortname: gc.GreedyShortIdConverter, *args): if len(args) == 0: self.bot.atSend(ctx, newChronicle_description) return fullname = " ".join(list(args)) # squish issuer = str(ctx.message.author.id) # todo existence t = self.bot.dbm.db.transaction() try: self.bot.dbm.db.insert("Chronicle", id=shortname, name = fullname) self.bot.dbm.db.insert("StoryTellerChronicleRel", storyteller=issuer, chronicle=shortname) except: t.rollback() raise else: t.commit() issuer_user = await self.bot.fetch_user(issuer) await self.bot.atSend(ctx, f"Cronaca {fullname} inserita ed associata a {issuer_user}") @gmadm.command(name = 'newTrait', brief = gmadm_help['newTrait'][1], description = newTrait_description) @commands.before_invoke(gs.command_security(gs.basicStoryTeller)) async def newTrait(self, ctx: commands.Context, traitid: gc.GreedyShortIdConverter, traittype: gc.TraitTypeConverter, tracktype: gc.TrackerTypeConverter, std: gc.NoYesConverter, *args): if len(args) == 0: await self.bot.atSend(ctx, newTrait_description) return istrait, _ = self.bot.dbm.validators.getValidateTrait(traitid).validate() if istrait: raise gb.BotException(f"Il tratto {traitid} esiste già!") traittypeid = traittype['id'] traitname = " ".join(args) response = "" t = self.bot.dbm.db.transaction() try: self.bot.dbm.db.insert("Trait", id = traitid, name = traitname, traittype = traittypeid, trackertype = tracktype, standard = std, ordering = 1.0) # we insert it in all available languages and we assume that it will be translated later: # better have it in the wrong language than not having it at all self.bot.dbm.db.query(query_addTraitLangs, vars = dict(traitid=traitid, traitname=traitname)) response = f'Il tratto {traitname} è stato inserito' if std: self.bot.dbm.db.query(query_addTraitToPCs, vars = dict(traitid=traitid)) response += f'\nIl nuovo tratto standard {traitname} è stato assegnato ai personaggi!' except: t.rollback() raise else: t.commit() await self.bot.atSend(ctx, response) @gmadm.command(name = 'updt', brief = gmadm_help['updt'][1], description = updt_description) @commands.before_invoke(gs.command_security(gs.basicStoryTeller)) async def updt(self, ctx: gb.GreedyContext, old_traitid: gc.GreedyShortIdConverter, new_traitid: gc.GreedyShortIdConverter, traittype: gc.TraitTypeConverter, tracktype: gc.TrackerTypeConverter, std: gc.NoYesConverter, *args): if len(args) == 0: await self.bot.atSend(ctx, newTrait_description) return istrait, old_trait = self.bot.dbm.validators.getValidateTrait( old_traitid).validate() if not istrait: raise gb.BotException(f"Il tratto {old_traitid} non esiste!") istrait, new_trait = self.bot.dbm.validators.getValidateTrait(new_traitid).validate() if istrait and (old_traitid!=new_traitid): raise gb.BotException(f"Il tratto {new_traitid} esiste già!") traittypeid = traittype['id'] traitname = " ".join(list(args)) response = f'Il tratto {traitname} è stato aggiornato' t = self.bot.dbm.db.transaction() try: self.bot.dbm.db.update("Trait", where= 'id = $oldid' , vars=dict(oldid = old_traitid), id = new_traitid, name = traitname, traittype = traittypeid, trackertype = tracktype, standard = std, ordering = 1.0) # now we update the language description, but only of the current language self.bot.dbm.db.update("LangTrait", where= 'traitId = $traitid and langId = $lid' , vars=dict(traitid=new_traitid, lid = ctx.getLID()), traitName = traitname) if std and not old_trait['standard']: self.bot.dbm.db.query(query_addTraitToPCs_safe, vars = dict(traitid=new_traitid)) response += f'\nIl nuovo talento standard {traitname} è stato assegnato ai personaggi!' elif not std and old_trait['standard']: self.bot.dbm.db.query(""" delete from CharacterTrait where trait = $traitid and max_value = 0 and cur_value = 0 and text_value = ''; """, vars = dict(traitid=new_traitid)) response += f'\nIl talento {traitname} è stato rimosso dai personaggi che non avevano pallini' except: t.rollback() raise else: t.commit() await self.bot.atSend(ctx, response) @gmadm.command(name = 'link', brief = gmadm_help['link'][1], description = link_description) @commands.before_invoke(gs.command_security(sec.OR(sec.IsAdmin, sec.AND( sec.OR(sec.IsActiveOnGuild, sec.IsPrivateChannelWithRegisteredUser), sec.genIsChronicleStoryteller(target_chronicle=2))))) async def link(self, ctx: commands.Context, chronicle: gc.ChronicleConverter, storyteller: gc.StorytellerConverter = None): issuer = str(ctx.message.author.id) chronid = chronicle['id'] target_st = None if storyteller == None: storyteller = await gc.StorytellerConverter().convert(ctx, issuer) target_st = storyteller['userid'] t_stc, _ = self.bot.dbm.isChronicleStoryteller(target_st, chronid) if t_stc: raise gb.BotException(f"L'utente selezionato è già Storyteller per {chronid}") # link self.bot.dbm.db.insert("StoryTellerChronicleRel", storyteller=target_st, chronicle=chronid) await self.bot.atSend(ctx, f"Cronaca associata") @gmadm.command(name = 'unlink', brief = gmadm_help['unlink'][1], description = unlink_description) @commands.before_invoke(gs.command_security(sec.OR(sec.IsAdmin, sec.AND( sec.OR(sec.IsActiveOnGuild, sec.IsPrivateChannelWithRegisteredUser), sec.genIsChronicleStoryteller(target_chronicle=2), sec.genIsSelf(optional_target_user=3))))) async def unlink(self, ctx: context.Context, chronicle: gc.ChronicleConverter, storyteller: gc.StorytellerConverter = None): issuer = str(ctx.message.author.id) chronid = chronicle['id'] target_st = None if storyteller == None: storyteller = await gc.StorytellerConverter().convert(ctx, issuer) target_st = storyteller['userid'] # link n = self.bot.dbm.db.delete('StoryTellerChronicleRel', where='storyteller=$storyteller and chronicle=$chronicle', vars=dict(storyteller=target_st, chronicle=chronid)) if n: await self.bot.atSend(ctx, f"Cronaca disassociata") else: await self.bot.atSend(ctx, f"Nessuna cronaca da disassociare") @gmadm.command(name = 'name', brief = gmadm_help['name'][1], description = name_description) @commands.before_invoke(gs.command_security(sec.IsAdmin)) async def name(self, ctx: commands.Context, user: gc.RegisteredUserConverter): target_st = user['userid'] name = user['name'] t_st, _ = self.bot.dbm.validators.getValidateBotStoryTeller(target_st).validate() if t_st: raise gb.BotException(f"L'utente selezionato è già uno storyteller") self.bot.dbm.db.insert("Storyteller", userid=target_st) await self.bot.atSend(ctx, f"{name} ora è Storyteller") @gmadm.command(name = 'unname', brief = gmadm_help['unname'][1], description = unname_description) @commands.before_invoke(gs.command_security(sec.IsAdmin)) async def unname(self, ctx: commands.Context, storyteller: gc.StorytellerConverter): target_st = storyteller['userid'] name = storyteller['name'] n = self.bot.dbm.unnameStoryTeller(target_st) if n: await self.bot.atSend(ctx, f"{name} non è più Storyteller") else: await self.bot.atSend(ctx, f"Nessuna modifica fatta") @gmadm.command(name = 'traittypes', brief = gmadm_help['traittypes'][1], description = traittypes_description) @commands.before_invoke(gs.command_security(gs.basicStoryTeller)) async def traittypes(self, ctx: commands.Context): ttypesl = self.bot.dbm.db.select('TraitType', what = "id, name").list() response = "Tipi di tratto: \n" response += "\n".join(list(map(lambda x : f"\t**{x['id']}**: {x['name']}", ttypesl))) await self.bot.atSend(ctx, response)
def mGET(self): return int(check_web_security(self, sec.OR(sec.IsAdmin, sec.AND( sec.IsUser, sec.genCanEditCharacter(target_character = 'charId')))))
def check_web_security(response: WebResponse, security_item: type[sec.CommandSecurity], **security_options) -> bool: """ Callable version of the web_security decorator. can be used to check a permission and get a boolean result """ decorator = web_security(security_item, **security_options) decorated = decorator(id) # it does not matter what we are decorating, so we just use id() try: decorated(response) return True except (sec.SecurityCheckException, sec.SecuritySetupError, sec.MissingParameterException) as e: return False except WebException: # in case we are using @langSupportExceptionTranslation return False # Security blocks canSeeCharacter = lambda target_character: sec.OR(sec.IsAdmin, sec.genIsCharacterStoryTeller(target_character), sec.genIsCharacterPlayer(target_character)) notesPermission = canSeeCharacter # --- STUFF --- def getLanguage(session: web.session.Session, dbm: ghostDB.DBManager) -> str: try: return dbm.getUserLanguage(session.discord_userid) except ghostDB.DBException: return default_language except AttributeError: return default_language def token_updater(token: str): session.oauth2_token = token
from typing import Any, Callable from greedy_components import greedyBase as gb from discord.ext import commands from support import security as sec from lang import lang as lng class BotSecurityCheckException(lng.LangSupportException, commands.CommandError): pass basicRegisteredUser: type[sec.CommandSecurity] = sec.OR( sec.IsAdmin, sec.AND(sec.IsUser, sec.IsActiveOnGuild), sec.IsPrivateChannelWithRegisteredUser) basicStoryTeller: type[sec.CommandSecurity] = sec.OR( sec.IsAdmin, sec.AND( sec.IsStoryteller, sec.OR(sec.IsActiveOnGuild, sec.IsPrivateChannelWithRegisteredUser))) def command_security(security_item: type[sec.CommandSecurity] = sec.NoCheck, *additional_security_items: type[sec.CommandSecurity], **security_options): """ Add security checks to a command with before_invoke, needs CommandSecurity objects as parameters If all the CommandSecurity items pass their checks, then the command executes. Example ---------