2023-12-15 21:00:29 +01:00
|
|
|
from django.db import models
|
|
|
|
from django.db.models import CASCADE
|
|
|
|
|
|
|
|
from zerver.models.users import UserProfile
|
|
|
|
|
|
|
|
# Interfaces for services
|
|
|
|
# They provide additional functionality like parsing message to obtain query URL, data to be sent to URL,
|
|
|
|
# and parsing the response.
|
|
|
|
GENERIC_INTERFACE = "GenericService"
|
|
|
|
SLACK_INTERFACE = "SlackOutgoingWebhookService"
|
|
|
|
|
|
|
|
|
|
|
|
# A Service corresponds to either an outgoing webhook bot or an embedded bot.
|
|
|
|
# The type of Service is determined by the bot_type field of the referenced
|
|
|
|
# UserProfile.
|
|
|
|
#
|
|
|
|
# If the Service is an outgoing webhook bot:
|
|
|
|
# - name is any human-readable identifier for the Service
|
|
|
|
# - base_url is the address of the third-party site
|
|
|
|
# - token is used for authentication with the third-party site
|
|
|
|
#
|
|
|
|
# If the Service is an embedded bot:
|
|
|
|
# - name is the canonical name for the type of bot (e.g. 'xkcd' for an instance
|
|
|
|
# of the xkcd bot); multiple embedded bots can have the same name, but all
|
|
|
|
# embedded bots with the same name will run the same code
|
|
|
|
# - base_url and token are currently unused
|
|
|
|
class Service(models.Model):
|
|
|
|
name = models.CharField(max_length=UserProfile.MAX_NAME_LENGTH)
|
|
|
|
# Bot user corresponding to the Service. The bot_type of this user
|
|
|
|
# determines the type of service. If non-bot services are added later,
|
|
|
|
# user_profile can also represent the owner of the Service.
|
|
|
|
user_profile = models.ForeignKey(UserProfile, on_delete=CASCADE)
|
|
|
|
base_url = models.TextField()
|
|
|
|
token = models.TextField()
|
|
|
|
# Interface / API version of the service.
|
|
|
|
interface = models.PositiveSmallIntegerField(default=1)
|
|
|
|
|
|
|
|
# Valid interfaces are {generic, zulip_bot_service, slack}
|
|
|
|
GENERIC = 1
|
|
|
|
SLACK = 2
|
|
|
|
|
|
|
|
ALLOWED_INTERFACE_TYPES = [
|
|
|
|
GENERIC,
|
|
|
|
SLACK,
|
|
|
|
]
|
|
|
|
# N.B. If we used Django's choice=... we would get this for free (kinda)
|
2024-07-12 02:30:17 +02:00
|
|
|
_interfaces: dict[int, str] = {
|
2023-12-15 21:00:29 +01:00
|
|
|
GENERIC: GENERIC_INTERFACE,
|
|
|
|
SLACK: SLACK_INTERFACE,
|
|
|
|
}
|
|
|
|
|
|
|
|
def interface_name(self) -> str:
|
|
|
|
# Raises KeyError if invalid
|
|
|
|
return self._interfaces[self.interface]
|
|
|
|
|
|
|
|
|
2024-07-12 02:30:17 +02:00
|
|
|
def get_bot_services(user_profile_id: int) -> list[Service]:
|
2023-12-15 21:00:29 +01:00
|
|
|
return list(Service.objects.filter(user_profile_id=user_profile_id))
|
|
|
|
|
|
|
|
|
|
|
|
def get_service_profile(user_profile_id: int, service_name: str) -> Service:
|
|
|
|
return Service.objects.get(user_profile_id=user_profile_id, name=service_name)
|
|
|
|
|
|
|
|
|
|
|
|
class BotStorageData(models.Model):
|
|
|
|
bot_profile = models.ForeignKey(UserProfile, on_delete=CASCADE)
|
|
|
|
key = models.TextField(db_index=True)
|
|
|
|
value = models.TextField()
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
unique_together = ("bot_profile", "key")
|
|
|
|
|
|
|
|
|
|
|
|
class BotConfigData(models.Model):
|
|
|
|
bot_profile = models.ForeignKey(UserProfile, on_delete=CASCADE)
|
|
|
|
key = models.TextField(db_index=True)
|
|
|
|
value = models.TextField()
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
unique_together = ("bot_profile", "key")
|