gdpr agreements

This commit is contained in:
Klemek
2021-04-09 14:57:55 +02:00
parent 0550a16c51
commit 6a70663201
5 changed files with 157 additions and 53 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
from .message_log import MessageLog from .message_log import MessageLog
from .channel_logs import ChannelLogs from .channel_logs import ChannelLogs
from .guild_logs import GuildLogs, ALREADY_RUNNING, CANCELLED from .guild_logs import GuildLogs, ALREADY_RUNNING, CANCELLED, NO_FILE
+29 -8
View File
@@ -23,11 +23,12 @@ current_analysis_lock = threading.Lock()
ALREADY_RUNNING = -100 ALREADY_RUNNING = -100
CANCELLED = -200 CANCELLED = -200
NO_FILE = -300
# 5 minutes, assume 'fast' arg # 5 minutes, assume 'fast' arg
MIN_MODIFICATION_TIME = 5 * 60 MIN_MODIFICATION_TIME = 5 * 60
# ~6 months, remove log file # ~1 year, remove log file
MAX_MODIFICATION_TIME = 6 * 30.5 * 24 * 60 * 60 MAX_MODIFICATION_TIME = 365 * 24 * 60 * 60
class Worker: class Worker:
@@ -110,7 +111,8 @@ class GuildLogs:
if not os.path.exists(LOG_DIR): if not os.path.exists(LOG_DIR):
os.mkdir(LOG_DIR) os.mkdir(LOG_DIR)
last_time = None last_time = None
if os.path.exists(self.log_file): if not os.path.exists(self.log_file):
return NO_FILE, 0
channels = {} channels = {}
try: try:
last_time = os.path.getmtime(self.log_file) last_time = os.path.getmtime(self.log_file)
@@ -126,9 +128,7 @@ class GuildLogs:
t0 = datetime.now() t0 = datetime.now()
json_data = gzip.decompress(gziped_data) json_data = gzip.decompress(gziped_data)
del gziped_data del gziped_data
logging.info( logging.info(f"log {self.guild.id} > gzip decompress in {delta(t0):,}ms")
f"log {self.guild.id} > gzip decompress in {delta(t0):,}ms"
)
if self.check_cancelled(): if self.check_cancelled():
return CANCELLED, 0 return CANCELLED, 0
await code_message(progress, "Reading saved history (3/4)...") await code_message(progress, "Reading saved history (3/4)...")
@@ -154,8 +154,6 @@ class GuildLogs:
logging.error(f"log {self.guild.id} > invalid JSON") logging.error(f"log {self.guild.id} > invalid JSON")
except IOError: except IOError:
logging.error(f"log {self.guild.id} > cannot read") logging.error(f"log {self.guild.id} > cannot read")
else:
fast = False
if len(target_channels) == 0: if len(target_channels) == 0:
target_channels = ( target_channels = (
@@ -327,6 +325,29 @@ class GuildLogs:
reference=message, reference=message,
) )
@staticmethod
def init_log(guild: List[discord.Guild]):
if not os.path.exists(LOG_DIR):
os.mkdir(LOG_DIR)
filename = os.path.join(LOG_DIR, f"{guild.id}{LOG_EXT}")
if not os.path.exists(filename):
with open(filename, mode="wb") as f:
f.write(gzip.compress(bytes("{}", "utf-8")))
logging.info(f"log {guild.id} > created")
else:
logging.info(f"log {guild.id} > already exists")
@staticmethod
def remove_log(guild: List[discord.Guild]):
if not os.path.exists(LOG_DIR):
os.mkdir(LOG_DIR)
filename = os.path.join(LOG_DIR, f"{guild.id}{LOG_EXT}")
if os.path.exists(filename):
os.unlink(filename)
logging.info(f"log {guild.id} > removed")
else:
logging.info(f"log {guild.id} > does not exists")
@staticmethod @staticmethod
def check_logs(guilds: List[discord.Guild]): def check_logs(guilds: List[discord.Guild]):
logging.info(f"checking logs...") logging.info(f"checking logs...")
+8 -2
View File
@@ -6,7 +6,7 @@ if sys.version_info < (3, 7):
print("Please upgrade your Python version to 3.7.0 or higher") print("Please upgrade your Python version to 3.7.0 or higher")
sys.exit(1) sys.exit(1)
from utils import emojis from utils import emojis, gdpr
from scanners import ( from scanners import (
EmotesScanner, EmotesScanner,
FullScanner, FullScanner,
@@ -57,7 +57,13 @@ bot.register_command(
"(cancel|stop)", "(cancel|stop)",
GuildLogs.cancel, GuildLogs.cancel,
"cancel: stop current analysis (not launched with fast)", "cancel: stop current analysis (not launched with fast)",
"```\n" + "%cancel: Stop current analysis (not launched with fast)\n" + "```", "```\n%cancel: Stop current analysis (not launched with fast)\n```",
)
bot.register_command(
"gdpr",
gdpr.process,
"gdpr: displays GDPR information",
gdpr.HELP,
) )
bot.register_command( bot.register_command(
"words", "words",
+11 -2
View File
@@ -5,8 +5,15 @@ import logging
import re import re
import discord import discord
from utils import no_duplicate, get_intro, delta from utils import no_duplicate, get_intro, delta, gdpr
from logs import GuildLogs, ChannelLogs, MessageLog, ALREADY_RUNNING, CANCELLED from logs import (
GuildLogs,
ChannelLogs,
MessageLog,
ALREADY_RUNNING,
CANCELLED,
NO_FILE,
)
class Scanner(ABC): class Scanner(ABC):
@@ -106,6 +113,8 @@ class Scanner(ABC):
"An analysis is already running on this server, please be patient.", "An analysis is already running on this server, please be patient.",
reference=message, reference=message,
) )
elif total_msg == NO_FILE:
await message.channel.send(gdpr.TEXT)
else: else:
self.msg_count = 0 self.msg_count = 0
self.total_msg = 0 self.total_msg = 0
+68
View File
@@ -0,0 +1,68 @@
import discord
from logs import GuildLogs
HELP = (
"```\n"
+ "%gdpr: Displays GDPR information\n"
+ "arguments:\n"
+ "* agree - agree to GDPR\n"
+ "* revoke - remove this server's data\n"
+ "```"
)
TEXT = (
""
+ "__**About Analyst-bot's data usage**__\n"
+ "**TL;DR**\n"
+ "Analyst-bot collects text message information. It does not share collected data with any third-party and data is retained 12 months or until the bot is leaving the guild/server.\n"
+ "**Data collection**\n"
+ "Analyst-bot collects a Discord guild/server's history when asked to.\n"
+ "This includes:\n"
+ "- Visible text channel names\n"
+ "- Visible text messages: date and time of creation and edition, author, content, reactions and other available metadata (pinned, tts, etc.)\n"
+ "This does __not__ includes:\n"
+ "- Voice channels and not visible channels\n"
+ "- Not visible text messages\n"
+ "- Visible text messages' embedded content, images and other attachments\n"
+ "**Data processing**\n"
+ "Any data collected is only processed in order to produce a one-time report sent to the user immediately. No temporary data are retained.\n"
+ "**Data storage and retain policy**\n"
+ "Analyst-bot stores the collected data in files that are accessible by the software and its administrator only.\n"
+ "Any collected data are retained maximum 12 months until deletion or when the bot is leaving a guild/server.\n"
+ "**Data sharing**\n"
+ "Analyst-bot does not share the data collected with any third-party.\n"
+ "**Right to retract**\n"
+ "If you want to have your data removed, you can use the `%gdpr revoke` command or remove this bot from your guild/server.\n"
+ "**Terms agreement**\n"
+ "By agreeing to these terms, you ensure having the legal age if you are in a country that does have one and you also ensure having the consent of every member involved.\n"
+ "\n"
+ "*If you want more information, please contact the creator of this bot: <https://github.com/Klemek/discord-analyst>.*\n"
+ "\n"
+ "Type `%gdpr agree` to agree to these terms, `%gdpr revoke` to remove this guild/server's collected data or `%gdpr` to see this message again."
)
AGREE_TEXT = "Thanks for agreeing for these terms, you can now run analysis on this guild/server."
REVOKE_TEXT = "This guild/server's data has been deleted. To run new analysis you must agree to the terms again."
async def process(client: discord.client, message: discord.Message, *args: str):
args = list(args)
if len(args) == 1:
await message.channel.send(TEXT)
elif len(args) > 2:
await message.channel.send(f"Too many arguments", reference=message)
elif args[1] == "help":
await message.channel.send(HELP, reference=message)
elif args[1] in ["agree", "accept"]:
GuildLogs.init_log(message.channel.guild)
await message.channel.send(AGREE_TEXT, reference=message)
elif args[1] in ["revoke", "cancel"]:
GuildLogs.remove_log(message.channel.guild)
await message.channel.send(REVOKE_TEXT, reference=message)
else:
await message.channel.send(
f"Unrecognized argument: `{args[1]}`", reference=message
)