Skip to content

Commit

Permalink
Data Models of PolicyTemplate and its Components (#594)
Browse files Browse the repository at this point in the history
* Allow more types of PolicyVariables, such as float and timestamp, and a list of basic data types; Allow specification of the entity of a policy variable

* Add functions in PolicyVariable to enforce the value of a policy variable to be the specified data types

* 1. Enforce policy variables to be the expected data type when building evaluation context;
2. Allow users to use policy variables in the attribute style

* Add Json-style CustomAction data model

* Create new permissions for custom actions with a community name

* Add FilterModule class

* Add Transformer (CheckModule) class

* Change the name of CheckModule to Transformer

* Add Procedure class

* Add PolicyTemplate class

* helper functions that help put all components into a policy template instance

* Implement to_json function of the PoicyTemplate class

* Tentatively remove codes about is_template policy

* Specify all filterable parameters for each Slack GovernableAction

* Specify schemas for execution parameters of each Slack GovernableAction

* Add a few community functions to support the need of new filters

* Add a few comments about parts of the data models that are temporary

* Adjust the Platform List from procedure to filter module as the latter is first defined

* Makemigrations according to updates of data models
  • Loading branch information
leijie-wang committed May 23, 2023
1 parent cf451e3 commit eba41df
Show file tree
Hide file tree
Showing 4 changed files with 898 additions and 61 deletions.
162 changes: 160 additions & 2 deletions policykit/integrations/slack/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,40 @@ def make_call(self, method_name, values={}, action=None, method=None):
class SlackPostMessage(GovernableAction):
ACTION = "chat.postMessage"
AUTH = "admin_bot"
EXECUTE_PARAMETERS = ["text", "channel"]
EXECUTE_PARAMETERS = ["text", "channel", "thread"]
FILTER_PARAMETERS = {"initiator": "CommunityUser", "text": "Text", "channel": None, "timestamp": None}
EXECUTE_VARIABLES = [
{
"name": "text",
"label": "Message to be posted",
"entity": None,
"default_value": "",
"is_required": True,
"prompt": "",
"type": "string",
"is_list": False
},
{
"name": "channel",
"label": "Channel to post message in",
"entity": "SlackChannel",
"default_value": "",
"is_required": True,
"prompt": "",
"type": "string",
"is_list": False
},
{
"name": "thread",
"label": "Thread timestamp to post message in",
"entity": None,
"default_value": "",
"is_required": False,
"prompt": "",
"type": "string",
"is_list": False
}
]

text = models.TextField()
channel = models.CharField("channel", max_length=150)
Expand All @@ -183,6 +216,29 @@ class SlackRenameConversation(GovernableAction):
ACTION = "conversations.rename"
AUTH = "admin_user"
EXECUTE_PARAMETERS = ["channel", "name"]
FILTER_PARAMETERS = {"initiator": "CommunityUser", "name": "Text", "previous_name": "Text", "channel": None}
EXECUTE_VARIABLES = [
{
"name": "channel",
"label": "Channel to rename",
"entity": "SlackChannel",
"default_value": "",
"is_required": True,
"prompt": "",
"type": "string",
"is_list": False
},
{
"name": "name",
"label": "New name for the channel",
"entity": None,
"default_value": "",
"is_required": True,
"prompt": "",
"type": "string",
"is_list": False
}
]

name = models.CharField("name", max_length=150)
channel = models.CharField("channel", max_length=150)
Expand All @@ -207,6 +263,29 @@ class SlackJoinConversation(GovernableAction):
ACTION = "conversations.invite"
AUTH = "admin_user"
EXECUTE_PARAMETERS = ["channel", "users"]
FILTER_PARAMETERS = {"initiator": "CommunityUser", "channel": None, "users": None}
EXECUTE_VARIABLES = [
{
"name": "channel",
"label": "Channel to join",
"entity": "SlackChannel",
"default_value": "",
"is_required": True,
"prompt": "",
"type": "string",
"is_list": False
},
{
"name": "users",
"label": "Users that will join the channel",
"entity": "SlackUser",
"default_value": "",
"is_required": True,
"prompt": "",
"type": "string",
"is_list": True
}
]

channel = models.CharField("channel", max_length=150)
users = models.CharField("users", max_length=15)
Expand All @@ -231,6 +310,30 @@ class SlackPinMessage(GovernableAction):
ACTION = "pins.add"
AUTH = "bot"
EXECUTE_PARAMETERS = ["channel", "timestamp"]
FILTER_PARAMETERS = {"initiator": "CommunityUser", "channel": None, "timestamp": "Timestamp"}
EXECUTE_VARIABLES = [
{
"name": "channel",
"label": "Channel that the message is pinned to",
"entity": "SlackChannel",
"default_value": "",
"is_required": True,
"prompt": "",
"type": "string",
"is_list": False
},
{
"name": "timestamp",
"label": "Timestamp of the message to pin",
"entity": None,
"default_value": "",
"is_required": True,
"prompt": "",
"type": "timestamp",
"is_list": False
}
]

channel = models.CharField("channel", max_length=150)
timestamp = models.CharField(max_length=32)

Expand All @@ -245,7 +348,39 @@ def _revert(self):
class SlackScheduleMessage(GovernableAction):
ACTION = "chat.scheduleMessage"
EXECUTE_PARAMETERS = ["text", "channel", "post_at"]

FILTER_PARAMETERS = {"text": "Text", "channel": None, "post_at": "Timestamp"}
EXECUTE_VARIABLES = [
{
"name": "text",
"label": "Text of the message to send",
"entity": None,
"default_value": "",
"is_required": True,
"prompt": "",
"type": "string",
"is_list": False
},
{
"name": "channel",
"label": "Channel that the message is scheduled to sent to",
"entity": "SlackChannel",
"default_value": "",
"is_required": True,
"prompt": "",
"type": "string",
"is_list": False
},
{
"name": "post_at",
"label": "Timestamp when the message is scheduled to send",
"entity": None,
"default_value": "",
"is_required": True,
"prompt": "",
"type": "timestamp",
"is_list": False
}
]
text = models.TextField()
channel = models.CharField("channel", max_length=150)
post_at = models.IntegerField("post at")
Expand All @@ -258,6 +393,29 @@ class SlackKickConversation(GovernableAction):
ACTION = "conversations.kick"
AUTH = "user"
EXECUTE_PARAMETERS = ["user", "channel"]
FILTER_PARAMETERS = {"initiator": "CommunityUser", "channel": None, "user": "CommunityUser"}
EXECUTE_VARIABLES = [
{
"name": "channel",
"label": "Channel to kick the user from",
"entity": "SlackChannel",
"default_value": "",
"is_required": True,
"prompt": "",
"type": "string",
"is_list": False
},
{
"name": "user",
"label": "User to kick from the channel",
"entity": "SlackUser",
"default_value": "",
"is_required": True,
"prompt": "",
"type": "string",
"is_list": False
}
]

user = models.CharField("user", max_length=15)
channel = models.CharField("channel", max_length=150)
Expand Down
6 changes: 3 additions & 3 deletions policykit/policyengine/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ def __init__(self, *args, **kwargs):
super(AttrDict, self).__init__(*args, **kwargs)
self.__dict__ = self


class EvaluationLogAdapter(logging.LoggerAdapter):
def process(self, msg, kwargs):
kwargs["extra"] = self.extra
Expand Down Expand Up @@ -80,9 +79,10 @@ def __init__(self, proposal):
setattr(self, comm.platform, comm)

self.metagov = Metagov(proposal)

# Make policy variables available in the evaluation context
setattr(self, "variables", AttrDict({ variable.name : variable.get_variable_values() for variable in self.policy.variables.all() or []}))

# Make policy variables available in the evaluation context
setattr(self, "variables", AttrDict({ v.name : v.value for v in self.policy.variables.all() or []}))

class PolicyEngineError(Exception):
"""Base class for exceptions raised from the policy engine"""
Expand Down
105 changes: 105 additions & 0 deletions policykit/policyengine/migrations/0018_auto_20230521_1821.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Generated by Django 3.2.2 on 2023-05-21 18:21

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('policyengine', '0017_alter_policy_community'),
]

operations = [
migrations.CreateModel(
name='CustomAction',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('is_trigger', models.BooleanField(default=False)),
('filter', models.TextField(blank=True, default='[]')),
('community_name', models.TextField(null=True, unique=True)),
('action_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='policyengine.actiontype')),
],
),
migrations.CreateModel(
name='Transformer',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.TextField(blank=True, default='', unique=True)),
('description', models.TextField(blank=True, default='')),
('codes', models.TextField(blank=True, default='')),
('variables', models.TextField(blank=True, default='[]')),
('data', models.TextField(blank=True, default='[]')),
],
),
migrations.RemoveField(
model_name='policy',
name='is_template',
),
migrations.AddField(
model_name='policyvariable',
name='entity',
field=models.CharField(blank=True, max_length=100, null=True),
),
migrations.AddField(
model_name='policyvariable',
name='is_list',
field=models.BooleanField(default=False),
),
migrations.AlterField(
model_name='policyvariable',
name='type',
field=models.CharField(choices=[('number', 'number'), ('string', 'string'), ('float', 'float'), ('timestamp', 'timestamp')], default='string', max_length=30),
),
migrations.CreateModel(
name='Procedure',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.TextField(blank=True, default='')),
('description', models.TextField(blank=True, default='')),
('platform', models.TextField(blank=True, choices=[('Slack', 'Slack'), ('Discord', 'Discord'), ('Discourse', 'Discourse'), ('Github', 'Github'), ('Opencollective', 'OpenCollective'), ('Reddit', 'Reddit'), ('All', 'All')], default='')),
('initialize', models.TextField(blank=True, default='[]')),
('check', models.TextField(blank=True, default='\\{\\}')),
('notify', models.TextField(blank=True, default='[]')),
('success', models.TextField(blank=True, default='[]')),
('fail', models.TextField(blank=True, default='[]')),
('variables', models.TextField(blank=True, default='[]')),
('data', models.TextField(blank=True, default='[]')),
],
options={
'unique_together': {('name', 'platform')},
},
),
migrations.CreateModel(
name='PolicyTemplate',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('description', models.TextField(blank=True, null=True)),
('kind', models.CharField(choices=[('platform', 'platform'), ('constitution', 'constitution'), ('trigger', 'trigger')], max_length=30)),
('is_trigger', models.BooleanField(default=False)),
('extra_executions', models.TextField(blank=True, default='{}')),
('variables', models.TextField(blank=True, default='[]')),
('data', models.TextField(blank=True, default='[]')),
('action_types', models.ManyToManyField(to='policyengine.ActionType')),
('custom_actions', models.ManyToManyField(to='policyengine.CustomAction')),
('procedure', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='policyengine.procedure')),
('transformers', models.ManyToManyField(to='policyengine.Transformer')),
],
),
migrations.CreateModel(
name='FilterModule',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('kind', models.TextField(blank=True, default='')),
('name', models.TextField(blank=True, default='')),
('description', models.TextField(blank=True, default='')),
('platform', models.TextField(blank=True, choices=[('Slack', 'Slack'), ('Discord', 'Discord'), ('Discourse', 'Discourse'), ('Github', 'Github'), ('Opencollective', 'OpenCollective'), ('Reddit', 'Reddit'), ('All', 'All')], default='All')),
('variables', models.TextField(blank=True, default='[]')),
('codes', models.TextField(blank=True, default='')),
],
options={
'unique_together': {('kind', 'name')},
},
),
]

0 comments on commit eba41df

Please sign in to comment.