Browse Source

Merge branch 'feature/simple-storage-options' of kirkleon/rollbot3 into master

kirkleon 6 years ago
parent
commit
d8dfa50095
4 changed files with 72 additions and 20 deletions
  1. 1 0
      .gitignore
  2. 34 15
      README.md
  3. 4 5
      mkplugin.sh
  4. 33 0
      src/command_system.py

+ 1 - 0
.gitignore

@@ -2,3 +2,4 @@ secrets.toml
 __pycache__/*
 *.pyc
 .venv
+.vscode/

+ 34 - 15
README.md

@@ -147,29 +147,48 @@ and run
 ./mkplugin my_cool_plugin
 ```
 
-This will end by printing something like
+This script will generate a file at `src/plugins/my_cool_plugin.py` containing (approximately)
 
-```
-Action required: Insert the following line into the [plugins] section of config/config.toml to activate my_cool_plugin
-my_cool_plugin = [ "my_cool_plugin"]
+```python
+from command_system import as_plugin
+
+
+@as_plugin
+def my_cool_plugin():
+    return "Hello, world!"
 ```
 
-Do as it says and open `config/config.toml` and add the printed line to the `[plugins]` map.
+The script also adds an `import plugins.my_cool_plugin` to `src/plugins/__init__.py`, so if you are
+reverting what this script did, remember to remove this import from that file. Only plugins imported
+in that top level module file will be available for the application, so if creating a plugin manually,
+you will need to add an import to that file.
 
-This script will also generate a file at `src/plugins/my_cool_plugin.py` containing
+The above script is the most basic possible rollbot plugin, which will simply respond with
+`Hello, world!` when it receives a message starting with `!my_cool_plugin`. The actual wiring of
+the plugin is handled by the `as_plugin` decorator, which performs all of the following:
+ - Inspects the name of your function and turns that into the command word. This can be overidden by
+ passing a single, string argument to `as_plugin`, which is detailed below.
+ - Inspects the arguments of your function, to determine what, if any, rollbot components need to be
+ passed into your function, which are detailed below.
+ - Wraps your plugin function to take any return values that are not instances of `RollbotResponse`
+ and convert them to strings, before wrapping them in a `RollbotResponse` with default settings, which
+ is detailed below.
+ - Generates a `RollbotPlugin` extension class which overrides the `on_command` method to call
+ your plugin function appropriately, and returns this class from the decorator, effectively assigning
+ it to the `my_cool_plugin` variable *instead* of your plugin function, which is what allows your
+ plugin to be found dynamically after just importing the plugin module
 
-```python
-from command_system import as_plugin, RollbotResponse
+#### Command Naming
 
+TODO
 
-@as_plugin("my_cool_plugin")
-def my_cool_plugin(db, msg):
-    return RollbotResponse(msg, txt="My first plugin!")
-```
+#### Plugin Arguments
+
+TODO
+
+#### RollbotResponse
 
-This is the most basic possible rollbot plugin, which will simply respond with `My first plugin!`
-when it receives a message starting with `!my_cool_plugin`. You can modify the argument to `as_plugin`
-to change the plugin's command word, which must be unique within the application.
+TODO
 
 Further docs to come! Good luck!
 

+ 4 - 5
mkplugin.sh

@@ -24,13 +24,12 @@ fi
 
 echo "Populating $PLUGIN_FILE with basic plugin called $1"
 
-echo "from command_system import as_plugin, RollbotResponse" >> $PLUGIN_FILE
+echo "from command_system import as_plugin" >> $PLUGIN_FILE
 echo "" >> $PLUGIN_FILE
 echo "" >> $PLUGIN_FILE
-echo "@as_plugin # if you want to change the name of the function below, you can just pass \"$1\" to this decorator" >> $PLUGIN_FILE
-echo "def $1(msg):" >> $PLUGIN_FILE
-echo "    # try adding db, bot, and log args, if you need those for your plugin" >> $PLUGIN_FILE
-echo "    return RollbotResponse(msg, txt=\"My first plugin!\")" >> $PLUGIN_FILE
+echo "@as_plugin" >> $PLUGIN_FILE
+echo "def $1():" >> $PLUGIN_FILE
+echo "    return \"Hello, world!\"" >> $PLUGIN_FILE
 
 echo "import plugins.$1" >> ./src/plugins/__init__.py
 

+ 33 - 0
src/command_system.py

@@ -4,6 +4,7 @@ from enum import Enum, auto
 import inspect
 import functools
 
+from sqlalchemy import Column, DateTime, Binary, String, Float, Integer
 from sqlalchemy.ext.declarative import declarative_base
 
 
@@ -12,6 +13,35 @@ BANGS = ('!',)
 ModelBase = declarative_base()
 
 
+class GroupBasedSingleton(ModelBase):
+    __tablename__ = "group_based_singleton"
+    group_id = Column(String, primary_key=True)
+    command_name = Column(String, primary_key=True)
+    subpart_name = Column(String, primary_key=True)
+    integer_data = Column(Integer)
+    float_data = Column(Float)
+    string_data = Column(String)
+    binary_data = Column(Binary)
+    datetime_data = Column(DateTime)
+
+    @staticmethod
+    def get_or_create(db, group_id, command_name, subpart_name):
+        sing = db.query(GroupBasedSingleton).get((group_id, command_name, subpart_name))
+        if sing is None:
+            sing = GroupBasedSingleton(
+                group_id=group_id,
+                command_name=command_name,
+                subpart_name=subpart_name,
+                integer_data=None,
+                float_data=None,
+                string_data=None,
+                binary_data=None,
+                datetime_data=None
+            )
+            db.add(sing)
+        return sing
+
+
 def pop_arg(text):
     if text is None:
         return None, None
@@ -171,6 +201,9 @@ def as_plugin(command):
                 converters.append(lambda self, db, msg: self.logger)
             elif p in ("bot", "rollbot"):
                 converters.append(lambda self, db, msg: self.bot)
+            elif p.startswith("data") or p.endswith("data") or p in ("group_singleton", "singleton"):
+                subp = fn.__annotations__.get(p, "")
+                converters.append(lambda self, db, msg, subp=subp: GroupBasedSingleton.get_or_create(db, msg.group_id, self.command, subp))
             else:
                 raise ValueError(f"Illegal argument name {p} in decorated plugin {command_name}")