List of commits:
Subject Hash Author Date (UTC)
Added comments to sources. ce6491ef1337ea34d33b7e4ede0eb9f634e7ab1a Detche 2016-10-22 23:32:26
Added examples. Modified reaction class to add triggers. 545a35d1c5bb36e1b4e4d818b0e6a8f6642a222f Detche 2016-10-22 20:56:54
Initial commit 2cd79df6224290a994b1453f0327740816b0f632 Detche 2016-10-21 16:21:02
Commit ce6491ef1337ea34d33b7e4ede0eb9f634e7ab1a - Added comments to sources.
Author: Detche
Author date (UTC): 2016-10-22 23:32
Committer name: Detche
Committer date (UTC): 2016-10-22 23:32
Parent(s): 545a35d1c5bb36e1b4e4d818b0e6a8f6642a222f
Signing key:
Tree: c0256f60f1cbdc62e182c0f0e4b616152c2c8581
File Lines added Lines deleted
botly/behaviour.py 12 5
botly/botly.py 24 16
botly/comm.py 19 17
botly/db.py 4 0
botly/knowledge.py 30 13
botly/reaction.py 53 43
botly/settings.py 20 15
botly/trigger.py 62 42
example.py 6 0
examplebot/reactions/EMPTY.py.example 3 1
examplebot/reactions/HELP.py.example 5 3
examplebot/reactions/sayhi.py 6 1
File botly/behaviour.py changed (mode: 100644) (index 102836f..d5908fd)
1 #!/usr/bin/env python
2 """This class groups by name of events the reactions of the Bot"""
3
1 4
2 5 class Behaviour: class Behaviour:
3
6 """Behaviour class holds the reaction sorted by event name."""
7
4 8 def __init__(self, reactions): def __init__(self, reactions):
5 9 self.reactions = {} self.reactions = {}
6 10 # We will group reactions based on the event # We will group reactions based on the event
 
... ... class Behaviour:
8 12 print('Loading reactions into behaviour...') print('Loading reactions into behaviour...')
9 13 for reaction in reactions: for reaction in reactions:
10 14 ename = reaction.get_event_name() ename = reaction.get_event_name()
11 print("Loading reaction '" + \
12 reaction.get_module_name() + \
13 "' into event table '" + \
14 ename + "'.")
15 print("Loading reaction '"
16 + reaction.get_module_name()
17 + "' into event table '"
18 + ename + "'.")
15 19 if not ename in self.reactions: if not ename in self.reactions:
16 20 self.reactions[ename] = [] self.reactions[ename] = []
17 21 self.reactions[ename].append(reaction) self.reactions[ename].append(reaction)
18 22
19 23 def get_reactions(self, eventName): def get_reactions(self, eventName):
24 """Returns reaction by event name given, or False it none exist."""
20 25 if eventName in self.reactions: if eventName in self.reactions:
21 26 return self.reactions[eventName] return self.reactions[eventName]
22 27 return False return False
28
29
File botly/botly.py changed (mode: 100644) (index bc6e6cf..0f835d9)
1 import discord
1 #!/usr/bin/env python
2 """Main class that will load the various parts of the bot."""
3
2 4 import asyncio import asyncio
3 import sys
4 import time
5 5
6 from .settings import Settings
7 from .knowledge import Knowledge
8 from .comm import Comm
9 from .reaction import load_reactions
10 from .behaviour import Behaviour
6 import discord
7
8 from botly.settings import Settings
9 from botly.knowledge import Knowledge
10 from botly.comm import Comm
11 from botly.reaction import load_reactions
12 from botly.behaviour import Behaviour
13
11 14
12 15 class Botly: class Botly:
16 """Main class that represents the bot. Will load various dependencies."""
13 17
14 18 def __init__(self, rootModule, dbPath): def __init__(self, rootModule, dbPath):
19 """Initialization loads database, reactions and tasks from drive."""
15 20 self.me = False self.me = False
16 21 self.comm = False self.comm = False
17 22
 
... ... class Botly:
19 24 self.settings.load(dbPath) self.settings.load(dbPath)
20 25 self.knowledge = Knowledge() self.knowledge = Knowledge()
21 26
22 self.behaviour = Behaviour(load_reactions(self, \
23 rootModule + '.reactions'))
27 self.behaviour = Behaviour(load_reactions(self,
28 rootModule + '.reactions'))
24 29
25 30 def live(self): def live(self):
31 """Runs the bot until it is exited. """
26 32 self.comm = Comm(self) self.comm = Comm(self)
27 33 # Listen to Discord's events (blocking call) # Listen to Discord's events (blocking call)
34 print("Connecting to Discord...")
28 35 self.comm.run() self.comm.run()
29 36 print("\nBotly exited.") print("\nBotly exited.")
30 37
31 38 def set_whoami(self, user): def set_whoami(self, user):
32 """
33 This will be called by Comm when Discord
34 has been connected.
35 """
39 """This will be called once the bot is connected to Discord."""
36 40 self.me = user self.me = user
37 41
38 42 async def react_to(self, eventName, **eventInfo): async def react_to(self, eventName, **eventInfo):
43 """Coroutine that will be called upon events. Checks for triggers."""
39 44 reactions = self.behaviour.get_reactions(eventName) reactions = self.behaviour.get_reactions(eventName)
40 45 if reactions: if reactions:
41 46 for reaction in reactions: for reaction in reactions:
42 if reaction.get_trigger().is_triggered(self, **eventInfo):
43 print('('+eventName+') -> ' + reaction.get_module_name())
47 if reaction.trigger.is_triggered(self, **eventInfo):
48 print("Reaction '" + reaction.moduleName
49 + "' triggered by event '" + eventName + "'.")
44 50 reaction.prepare_react(**eventInfo) reaction.prepare_react(**eventInfo)
45 51 await reaction.react() await reaction.react()
46 52
47 53 async def leave(self): async def leave(self):
54 """Coroutine that disconnects the robot from Discord."""
48 55 await self.comm.logout() await self.comm.logout()
49 56
57
File botly/comm.py changed (mode: 100644) (index 9e61871..6fd9842)
1 import discord
1 #!/usr/bin/env python
2 """Inherits from Discord client. Handles events and pass them to Botly."""
3
2 4 import asyncio import asyncio
3 import sys
4 import time
5
6 import discord
7
5 8
6 9 class Comm(discord.Client): class Comm(discord.Client):
7
10 """Inherits from discord.client. Used for communication with server."""
11
8 12 def __init__(self, botly): def __init__(self, botly):
9 13 self.botly = botly self.botly = botly
10 self.updatedBot = False
11 super(Comm, self).__init__(max_messages=botly.settings.get_int( \
12 'CacheMaxMessages'))
14 super(Comm, self).__init__(max_messages=botly.settings.get_int(
15 'CacheMaxMessages'))
13 16
14 17 async def on_ready(self): async def on_ready(self):
15 print('Bot ready')
16 if not self.updatedBot:
17 self.botly.set_whoami(self.user)
18 self.updatedBot = True
18 print('Bot ready. Press Ctrl+C to shutdown.')
19 self.botly.set_whoami(self.user)
19 20 await self.botly.react_to('on_ready') await self.botly.react_to('on_ready')
20 21
21 22 async def on_typing(self, channel, user, when): async def on_typing(self, channel, user, when):
22 23 if user != self.user: if user != self.user:
23 24 await self.botly.react_to('on_typing', channel=channel, user=user, await self.botly.react_to('on_typing', channel=channel, user=user,
24 when=when)
25 when=when)
25 26
26 27 async def on_message_edit(self, before, after): async def on_message_edit(self, before, after):
27 28 if before.author != self.user: if before.author != self.user:
28 await self.botly.react_to('on_message_edit', message=before, \
29 after=after)
29 await self.botly.react_to('on_message_edit', message=before,
30 after=after)
30 31
31 32 async def on_message_delete(self, message): async def on_message_delete(self, message):
32 33 if message.author != self.user: if message.author != self.user:
 
... ... class Comm(discord.Client):
37 38 await self.botly.react_to('on_message', message=message) await self.botly.react_to('on_message', message=message)
38 39
39 40 async def on_member_update(self, before, after): async def on_member_update(self, before, after):
40 await self.botly.react_to('on_member_update', before=before, \
41 after=after)
41 await self.botly.react_to('on_member_update', before=before,
42 after=after)
42 43
43 44 def run(self): def run(self):
44 45 super(Comm, self).run(self.botly.settings.get_string('DiscordToken')) super(Comm, self).run(self.botly.settings.get_string('DiscordToken'))
45
46
47
File botly/db.py changed (mode: 100644) (index 1a3614e..ec32975)
1 #!/usr/bin/env python
2 """Database class that loads the XML db, shared with daugther db classes."""
3
1 4 from lxml import etree from lxml import etree
2 5
3 6
 
... ... class Db:
18 21 else: else:
19 22 return 'None' return 'None'
20 23
24
File botly/knowledge.py changed (mode: 100644) (index bce2dea..cb5b41d)
1 from .db import Db
1 #!/usr/bin/env python
2 """Class Knowledge represents what bot knows, such as users and their info."""
3
4 from botly.db import Db
5
2 6
3 7 class Knowledge(Db): class Knowledge(Db):
4
8 """Represents what bot knows. Use accessors to access data."""
9
5 10 def __init__(self): def __init__(self):
6 11 self.users = [] self.users = []
7 12
8 def _load_users(self):
9 assert self.is_loaded(), 'Xml document is not loaded'
10 self.users = []
11 for userxml in Db.dbxml.xpath('/BotDb/Knowledge/Users/User'):
12 user = {}
13 user['Id'] = self.get_value(userxml, 'Id')
14 user['Alias'] = self.get_value(userxml, 'Alias')
15 user['BotAffinity'] = self.get_value(userxml, 'BotAffinity')
16 user['IsMaster'] = self.get_value(userxml, 'IsMaster')
17 self.users.append(user)
18
19 13 def get_users(self): def get_users(self):
14 """Returns the whole users table. Loads it from XML if not done yet."""
20 15 if len(self.users) == 0: if len(self.users) == 0:
21 16 self._load_users() self._load_users()
22 17 return self.users return self.users
23 18
19 def user_exists(self, id):
20 """Returns whether or not we have this user in our knowledge db."""
21 return True if self.get_user(id) else False
22
24 23 def get_user(self, id): def get_user(self, id):
24 """Return all botly values for given user id."""
25 25 for user in self.get_users(): for user in self.get_users():
26 26 if user['Id'] == id: if user['Id'] == id:
27 27 return user return user
28 28 return False return False
29 29
30 30 def get_user_affinity(self, id): def get_user_affinity(self, id):
31 """Returns the affinity of the user designated by given id."""
31 32 user = self.get_user(id) user = self.get_user(id)
32 33 if user == False: if user == False:
33 34 # We have an affinity of 0 (neutral) for unknown users # We have an affinity of 0 (neutral) for unknown users
 
... ... class Knowledge(Db):
35 36 return int(user['BotAffinity']) return int(user['BotAffinity'])
36 37
37 38 def get_user_alias(self, id): def get_user_alias(self, id):
39 """Returns the alias of the user designated by given id."""
38 40 user = self.get_user(id) user = self.get_user(id)
39 41 if user == False: if user == False:
40 42 return False return False
41 43 return user['Alias'] return user['Alias']
42 44
43 45 def is_user_master(self, id): def is_user_master(self, id):
46 """Returns whether or not user is a master (can command bot)."""
44 47 user = self.get_user(id) user = self.get_user(id)
45 48 if user == False: if user == False:
46 49 return False return False
47 50 return user['IsMaster'] == '1' return user['IsMaster'] == '1'
48 51
52 def _load_users(self):
53 # TODO, Change how users are loaded. Don't load them all at start, but
54 # only when requested. Also include non-hardcoded possible value.
55 assert self.is_loaded(), 'Xml document is not loaded'
56 self.users = []
57 for userxml in Db.dbxml.xpath('/BotDb/Knowledge/Users/User'):
58 user = {}
59 user['Id'] = self.get_value(userxml, 'Id')
60 user['Alias'] = self.get_value(userxml, 'Alias')
61 user['BotAffinity'] = self.get_value(userxml, 'BotAffinity')
62 user['IsMaster'] = self.get_value(userxml, 'IsMaster')
63 self.users.append(user)
64
65
File botly/reaction.py changed (mode: 100644) (index 098ae11..258432e)
1 #!/usr/bin/env python
2 """Contains the ReactionBase class, meant to be subclassed."""
3
1 4 import asyncio import asyncio
2 5 from importlib import import_module from importlib import import_module
3 6 from os import listdir from os import listdir
4 7 from os.path import isfile, join from os.path import isfile, join
5 8
6 from .trigger import Trigger
9 from botly.trigger import Trigger
10
7 11
8 12 class ReactionBase: class ReactionBase:
13 """Meant"""
14
9 15 def __init__(self, eventName): def __init__(self, eventName):
10 """
11 Subclass this and pass the event that this
12 reaction should react and the trigger object to
13 to the mother class constructor.
14 """
16 """When subclassed, pass the event name to the mother class."""
15 17 self.eventName = eventName self.eventName = eventName
16 18 self.botly = False self.botly = False
17 19 self.knowledge = False self.knowledge = False
 
... ... class ReactionBase:
19 21 # Call the function that should have been subclassed # Call the function that should have been subclassed
20 22 self.prepare_trigger(trigger) self.prepare_trigger(trigger)
21 23 self.trigger = trigger self.trigger = trigger
22
24
23 25 def prepare_trigger(self, trigger): def prepare_trigger(self, trigger):
26 """Allows the trigger to be personalized. Meant to be subclassed.
27
28 This method should be redefined in the subclass.
29 It should prepare the given trigger by defining its conditions.
30 It does not require to return anything
24 31 """ """
25 This method should be redefined in the subclass.
26 It should prepare the given trigger by defining its
27 conditions.
28 """
29 32 pass pass
30 33
34 async def react(self):
35 """Method to be subclassed. Called when conditions were met."""
36 pass
37
38 def print(self, message):
39 """Helper for console printing. Will prepend current Reaction name."""
40 print('[{0}] {1}'.format(self.moduleName, message))
41
42 def is_mentioned(self):
43 """Returns whether or not our bot was mentioned in the message."""
44 assert self.botly, 'Botly instance not passed to this object'
45 if self.message:
46 return self.botly.me.mentioned_in(self.message)
47
48 async def reply(self, message):
49 """Coroutine that replies in current chan with given message."""
50 if self.channel:
51 await self.botly.comm.send_message(self.channel, message)
52
53 async def send_to_chan(self, channel, message):
54 """Coroutine that send message to given channel."""
55 await self.botly.comm.send_message(channel, message)
56
31 57 def set_botly_instance(self, botly): def set_botly_instance(self, botly):
58 """Saves botly instance. Only meant to becalled upon module import."""
32 59 self.botly = botly self.botly = botly
33 60 self.knowledge = botly.knowledge self.knowledge = botly.knowledge
34 61
35 62 def set_module_name(self, name): def set_module_name(self, name):
63 """Saves the name of this Reaction. Called upon module import."""
36 64 self.moduleName = name self.moduleName = name
37
38 def get_trigger(self):
39 return self.trigger
40
41 def get_module_name(self):
42 return self.moduleName
43
44 def get_event_name(self):
45 return self.eventName
46 65
47 66 def prepare_react(self, **eventInfo): def prepare_react(self, **eventInfo):
67 """Only meant to be called from Botly. Do not call elsewhere."""
48 68 self.message = False self.message = False
49 69 self.messageAfter = False self.messageAfter = False
50 70 self.author = False self.author = False
 
... ... class ReactionBase:
68 88 self.before = eventInfo['before'] self.before = eventInfo['before']
69 89 self.after = eventInfo['after'] self.after = eventInfo['after']
70 90
71 def is_mentioned(self):
72 assert self.botly, 'Botly instance not passed to this object'
73 if self.message:
74 return self.botly.me.mentioned_in(self.message)
75
76 async def reply(self, message):
77 if self.channel:
78 self.botly.comm.send_message(self.channel, message)
79
80 async def reply_to_chan(self, channel, message):
81 self.botly.comm.send_message(channel, message)
82
83 async def react(self):
84 """
85 Method to be subclassed.
86 This will be called when the triggers will be triggered.
87 """
88 pass
89
90 91 def load_reactions(botly, reactionsParent): def load_reactions(botly, reactionsParent):
92 """Function that loads reactions from given parent module directory."""
93 # Convert module path to drive path.
91 94 dpath = './' + reactionsParent.replace('.', '/') dpath = './' + reactionsParent.replace('.', '/')
92 files = [f for f in listdir(dpath) \
93 if isfile(join(dpath,f)) \
95
96 # Retreive every python script in the reaction module directory
97 files = [f for f in listdir(dpath)
98 if isfile(join(dpath,f))
94 99 and f.endswith('.py')] and f.endswith('.py')]
100
101 # Build the list of reactions
95 102 reactions = [] reactions = []
96 103 for file in files: for file in files:
104 # Module name does not include '.py' so remove that part
97 105 module = file[:-3] module = file[:-3]
98 106 _reaction = import_module(reactionsParent + '.' + module) _reaction = import_module(reactionsParent + '.' + module)
99 107 reaction = _reaction.Reaction() reaction = _reaction.Reaction()
108 reactions.append(reaction)
100 109 assert len(reaction.get_event_name()), \ assert len(reaction.get_event_name()), \
101 110 'Loaded a reaction linked to no event.' 'Loaded a reaction linked to no event.'
111 # Inject instance info in reaction object
102 112 reaction.set_botly_instance(botly) reaction.set_botly_instance(botly)
103 113 reaction.set_module_name(module) reaction.set_module_name(module)
104 reactions.append(reaction)
105 print('Loaded '+str(len(reactions))+' reactions from drive.')
114 print('Loaded ' + str(len(reactions)) + ' reactions from drive.')
106 115 return reactions return reactions
107 116
117
File botly/settings.py changed (mode: 100644) (index a68773d..bad6ea3)
1 from .db import Db
1 #!/usr/bin/env python
2 """Loads and manages the bot settings."""
3
4 from botly.db import Db
5
2 6
3 7 class Settings(Db): class Settings(Db):
4 8
5 9 def __init__(self): def __init__(self):
6 10 self.settings = {} self.settings = {}
7 11
8 def _load_setting(self, key):
9 assert self.is_loaded(), "Database is not loaded."
10 value = 'None'
11 setting = Db.dbxml.xpath('/BotDb/Settings/' + key)
12 if setting:
13 value = setting[0].text
14 return value
15
16 def get_string(self, key, default = False):
12 def get_string(self, key, default='None'):
13 """Returns the string value if it exists."""
17 14 if not key in self.settings: if not key in self.settings:
18 self.settings[key] = self._load_setting(key)
15 self.settings[key] = self._load_setting(key, default)
19 16 return self.settings[key] return self.settings[key]
20 17
21 def get_int(self, key, default = False):
22 v = self.get_string(key)
23 if v == 'None':
24 return '0'
18 def get_int(self, key, default='0'):
19 """Returns the int value if it exists."""
20 # Default default is a string because passed to get_string.
21 # It's converted back to int below
22 v = self.get_string(key, default=default)
25 23 return int(v) return int(v)
26 24
25 def _load_setting(self, key, default):
26 assert self.is_loaded(), "Database is not loaded."
27 setting = Db.dbxml.xpath('/BotDb/Settings/' + key)
28 if setting:
29 return setting[0].text
30 else:
31 return default
File botly/trigger.py changed (mode: 100644) (index 871224c..6a06731)
1 import discord
1 #!/usr/bin/env python
2 """Trigger class defines condition for a Reaction to trigger."""
3
2 4 import re import re
3 import random
5 from random import randrange
6
7 import discord
8
9 from botly.knowledge import Knowledge
4 10
5 from .knowledge import Knowledge
6 11
7 12 class Trigger: class Trigger:
13 """Defienes and check for the conditions."""
14
8 15 def __init__(self, eventName): def __init__(self, eventName):
9 16 self.eventName = eventName self.eventName = eventName
10 17 self.conditions = [] self.conditions = []
 
... ... class Trigger:
12 19 self.requireMention = False self.requireMention = False
13 20 self.triggerChance = 100 self.triggerChance = 100
14 21
15 def _pattern_valid(self, pattern):
16 try:
17 re.compile(pattern)
18 return True
19 except re.error:
20 return False
21 22
22 23 def add_condition(self, variable, pattern): def add_condition(self, variable, pattern):
24 """Add a simple condition where variable should match the pattern.
25
26 The possible variable names are 'message' and 'author'.
27 The pattern is a Regular Expression pattern that should respect
28 the standard regex format. More information on this in the Python
29 documentation.
23 30 """ """
24 Add a condition where given variable should match given
25 regular expression pattern.
26 """
27 assert self._pattern_valid(pattern), 'Given pattern is invalid.'
31 assert self._is_pattern_valid(pattern), \
32 'Given regular expression pattern is invalid.'
28 33
29 34 if 'message' == variable: if 'message' == variable:
30 35 assert 'message' in self.eventName, \ assert 'message' in self.eventName, \
31 'message variable not expected for this event'
36 'message variable not expected for this event.'
32 37 elif 'author' == variable: elif 'author' == variable:
33 38 assert eventName != 'on_ready', \ assert eventName != 'on_ready', \
34 'author not supported for on_ready event'
39 'author not supported for on_ready event.'
35 40
36 41 condition = [] condition = []
37 42 condition.append(variable) condition.append(variable)
 
... ... class Trigger:
39 44 self.conditions.append(condition) self.conditions.append(condition)
40 45
41 46 def add_adv_condition(self, callback): def add_adv_condition(self, callback):
42 """
43 Added a function as the condition. It should return
44 True if the condition is respected or False if not.
45 It will be called with the full event info table.
47 """Add a condition based on a callback variable.
48
49 The function will be called upon trigger verification.
50 It should return True if the condition is respected or False if not.
51 The event info table will be passed as an argument
46 52 """ """
47 53 assert callable(callback), 'Given argument must be a callback function' assert callable(callback), 'Given argument must be a callback function'
48 54 self.advConditions.append(callback) self.advConditions.append(callback)
49 55
50 56 def set_trigger_chance(self, percent): def set_trigger_chance(self, percent):
51 assert isinstance(value, int), 'Int expected.'
57 assert isinstance(value, int), 'Int expected for trigger chance.'
52 58 percent = percent if percent >= 1 else 1 percent = percent if percent >= 1 else 1
53 59 percent = percent if percent <= 100 else 100 percent = percent if percent <= 100 else 100
54 60 self.triggerChance = percent self.triggerChance = percent
55 61
56 62 def require_mention(self, value): def require_mention(self, value):
57 assert isinstance(value, bool), 'Bool expected.'
63 """Defines whether or not tihs bot has to be mentioned for trigger."""
64 assert isinstance(value, bool), 'Bool expected for require mention.'
58 65 self.requireMention = value self.requireMention = value
59 66
67 def is_triggered(self, botly, **eventInfo):
68 """This should only be called from Botly class.
69
70 Checks whether or not the trigger object activates based on the
71 given information. This is meant to be called from the Botly class
72 that processes events and check for triggers.
73 """
74 # Run random. Do we have a chance to trigger?
75 if not self._can_we_trigger():
76 return False
77
78 # Checks if bot is mentioned if it is required:
79 if self.requireMention and 'message' in self.eventName:
80 if not botly.me.mentioned_in(eventInfo['message']):
81 return False
82
83 # Check for conditions:
84 for condition in self.conditions:
85 if not self._is_condition_true(condition, **eventInfo):
86 return False
87
88 # Check advanced conditions:
89 for condition in self.advConditions:
90 if not condition(**eventInfo):
91 return False
92
93 return True
94
60 95 def _can_we_trigger(self): def _can_we_trigger(self):
61 96 if self.triggerChance == 100: if self.triggerChance == 100:
62 97 return True return True
63 return random.randrange(1, 101) < self.triggerChance
98 return randrange(1, 101) < self.triggerChance
64 99
65 100 def _is_condition_true(self, condition, **eventInfo): def _is_condition_true(self, condition, **eventInfo):
66 101 v = condition[0] v = condition[0]
 
... ... class Trigger:
78 113 if re.match(p, eventInfo['message'].content): if re.match(p, eventInfo['message'].content):
79 114 return True return True
80 115
81 def is_triggered(self, botly, **eventInfo):
82 # Run random. Do we have a chance to trigger?
83 if not self._can_we_trigger():
116 def _is_pattern_valid(self, pattern):
117 try:
118 re.compile(pattern)
119 return True
120 except re.error:
84 121 return False return False
85
86 # Checks if bot is mentioned if it is required:
87 if 'message' in self.eventName and self.requireMention:
88 if not botly.me.mentioned_in(eventInfo['message']):
89 return False
90
91 # Check for conditions:
92 for condition in self.conditions:
93 if not self._is_condition_true(condition, **eventInfo):
94 return False
95 122
96 # Check advanced conditions:
97 for condition in self.advConditions:
98 if not condition(**eventInfo):
99 return False
100
101 # We trigger yo.
102 return True
103 123
File example.py changed (mode: 100644) (index dba7f91..96e4ba8)
1 #!/usr/bin/env python
2
1 3 from botly.botly import Botly from botly.botly import Botly
2 4
5
3 6 def main(): def main():
4 7 bot = Botly('examplebot', 'examplebot/botdb.xml') bot = Botly('examplebot', 'examplebot/botdb.xml')
5 8 bot.live() bot.live()
6 9
10
7 11 if __name__ == "__main__": if __name__ == "__main__":
8 12 main() main()
13
14
File examplebot/reactions/EMPTY.py.example changed (mode: 100644) (index d6ce171..c49ccb6)
1 import discord
2
1 3 from botly.reaction import ReactionBase from botly.reaction import ReactionBase
2 4 from botly.trigger import Trigger from botly.trigger import Trigger
3 import discord
5
4 6
5 7 class Reaction(ReactionBase): class Reaction(ReactionBase):
6 8
File examplebot/reactions/HELP.py.example changed (mode: 100644) (index ac94ff8..1cb51e7)
1 import discord
2
1 3 from botly.reaction import ReactionBase from botly.reaction import ReactionBase
2 4 from botly.trigger import Trigger from botly.trigger import Trigger
3 import discord
5
4 6
5 7 class Reaction(ReactionBase): class Reaction(ReactionBase):
6 8
 
... ... class Reaction(ReactionBase):
37 39 # False. # False.
38 40 # #
39 41 # def myCallback(**eventInfo): # def myCallback(**eventInfo):
40 # if eventInfo['message'].content == 'prout' \
41 # and eventInfo['message'].author.name == 'Blaise':
42 # if (eventInfo['message'].content == 'prout'
43 # and eventInfo['message'].author.name == 'Blaise'):
42 44 # return True # return True
43 45 # return False # return False
44 46 # #
File examplebot/reactions/sayhi.py changed (mode: 100644) (index e4ee71d..78d8338)
1 #!/usr/bin/env python
2 """Reaction: Bot will respond to hello messages based on user affinity."""
3
4 import discord
5
1 6 from botly.reaction import ReactionBase from botly.reaction import ReactionBase
2 7 from botly.trigger import Trigger from botly.trigger import Trigger
3 import discord
8
4 9
5 10 class Reaction(ReactionBase): class Reaction(ReactionBase):
6 11
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/detche/Botly

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/detche/Botly

Clone this repository using git:
git clone git://git.rocketgit.com/user/detche/Botly

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main