maintenance/fs.py
[pub/jan/mattermost-privileged.git] / profile_badges / main.py
1 #!/usr/bin/env -S python3 -Bu
2 # Someone's Mattermost scripts.
3 #   Copyright (c) 2016-2022 by Someone <someone@somenet.org> (aka. Jan Vales <jan@jvales.net>)
4 #   published under MIT-License
5 #
6 # Custom profile badges.
7 #
8
9 import psycopg2
10 import psycopg2.extras
11 from inspect import cleandoc
12
13 import mattermost
14
15 import config
16
17 mm = mattermost.MMApi(config.mm_api_url)
18 mm.login(config.mm_user, config.mm_user_pw)
19
20 cfg = mm._get("/v4/config")
21 cfg["PluginSettings"]["Enable"] = True
22 cfg["PluginSettings"]["PluginStates"]["com.mattermost.custom-attributes"]["Enable"] = True
23 cfg["PluginSettings"]["Plugins"]["com.mattermost.custom-attributes"]["customattributes"] = []
24
25 # Im a bot!
26 bot_ids = [mm._my_user_id]
27 bot_ids.extend(config.bot_ids)
28 cfg["PluginSettings"]["Plugins"]["com.mattermost.custom-attributes"]["customattributes"].append({"Name": ":robot:[**``Bot (software agent)``**](https://en.wikipedia.org/wiki/Software_agent)", "UserIDs": bot_ids})
29
30
31 #####################################
32 # post-based badges + 2k+posts club #
33 #####################################
34 if hasattr(config, "dbconnstring") and hasattr(config, "club_team_id") and hasattr(config, "club_id") :
35     dbconn = psycopg2.connect(config.dbconnstring)
36     dbconn.set_session(autocommit=False)
37
38     cur = dbconn.cursor(cursor_factory=psycopg2.extras.DictCursor)
39     cur.execute("""SELECT users.id AS id, username, count(*) AS posts, SUM(LENGTH(posts.message)) AS chars FROM posts JOIN users ON(users.id = userid)
40                 WHERE posts.userid != ALL(%(club_banned_uids)s) AND posts.deleteat = 0 AND NOT posts.props::jsonb @> '{"from_webhook":"true"}'::jsonb AND posts.createat > EXTRACT(EPOCH FROM (NOW() - INTERVAL '7 day'))*1000
41                 GROUP BY users.id, username ORDER BY posts DESC LIMIT 1
42                 """, {"club_banned_uids":config.club_banned_uids})
43     sotw = cur.fetchall()[0]
44     cfg["PluginSettings"]["Plugins"]["com.mattermost.custom-attributes"]["customattributes"].append({"Name": ":crown: **``Spammer of the week ("+str(sotw["posts"])+")``**", "UserIDs": [sotw["id"]]})
45
46     cur = dbconn.cursor(cursor_factory=psycopg2.extras.DictCursor)
47     cur.execute("""SELECT users.id AS id, username, count(*) AS posts, SUM(LENGTH(posts.message)) AS chars FROM posts JOIN users ON(users.id = userid)
48                 WHERE posts.userid != ALL(%(club_banned_uids)s) AND posts.deleteat = 0 AND NOT posts.props::jsonb @> '{"from_webhook":"true"}'::jsonb AND posts.createat > EXTRACT(EPOCH FROM (NOW() - INTERVAL '7 day'))*1000
49                 GROUP BY users.id, username ORDER BY chars DESC LIMIT 1
50                 """, {"club_banned_uids":config.club_banned_uids})
51     sotwc = cur.fetchall()[0]
52     cfg["PluginSettings"]["Plugins"]["com.mattermost.custom-attributes"]["customattributes"].append({"Name": ":crown: **``Spammer of the week ("+str(sotwc["chars"])+")``**", "UserIDs": [sotwc["id"]]})
53
54
55     pbb = [
56         {"Name": "placeholder1", "UserIDs": []},
57         {"Name": "placeholder2", "UserIDs": []},
58         {"Name": "placeholder3", "UserIDs": []},
59         {"Name": ":envelope::medal_sports:``50000+ posts``", "UserIDs": []},
60         {"Name": ":envelope::medal_sports:``20000+ posts``", "UserIDs": []},
61         {"Name": ":envelope::medal_sports:``10000+ posts``", "UserIDs": []},
62         {"Name": ":envelope::medal_sports:``5000+ posts``", "UserIDs": []},
63         {"Name": ":envelope::medal_sports:``2000+ posts``", "UserIDs": []},
64         {"Name": ":envelope:``1000+ posts``", "UserIDs": []},
65         {"Name": ":envelope:``500+ posts``", "UserIDs": []},
66         {"Name": ":envelope:``200+ posts``", "UserIDs": []},
67         {"Name": ":envelope:``100+ posts``", "UserIDs": []},
68         {"Name": ":envelope:``50+ posts``", "UserIDs": []},
69         {"Name": ":envelope:``10+ posts``", "UserIDs": []},
70         {"Name": ":envelope::medal_military:``Less than 10 posts``", "UserIDs": []},
71         ]
72
73     cur = dbconn.cursor(cursor_factory=psycopg2.extras.DictCursor)
74     cur.execute("""SELECT users.id AS id, username, count(*) AS posts, SUM(LENGTH(posts.message)) AS chars FROM posts JOIN users ON(users.id = userid)
75                 WHERE posts.deleteat = 0 AND NOT posts.props::jsonb @> '{"from_webhook":"true"}'::jsonb AND posts.createat < EXTRACT(EPOCH FROM (NOW() - INTERVAL '7 day'))*1000
76                 GROUP BY users.id, username ORDER BY posts DESC
77                 """)
78     last_week_post_pos = [[r["id"], r["posts"], r["chars"]] for r in cur.fetchall()]
79     last_week_post_statsres = {x[0]:[x[1], x[2]] for x in last_week_post_pos}
80     last_week_post_pos = [x[0] for x in last_week_post_pos if x[0] not in config.club_banned_uids]
81
82
83     cur = dbconn.cursor(cursor_factory=psycopg2.extras.DictCursor)
84     cur.execute("""SELECT users.id AS id, username, count(*) AS posts, SUM(LENGTH(posts.message)) AS chars FROM posts JOIN users ON (users.id = userid)
85                 WHERE posts.deleteat = 0 AND NOT posts.props::jsonb @> '{"from_webhook":"true"}'::jsonb
86                 GROUP BY users.id, username ORDER BY posts DESC
87                 """)
88
89     msg = cleandoc("""Post-Stats. #mmstats
90     :crown: SOTW (Spammer-of-the-week): **@"""+sotw["username"]+"""** ("""+str(sotw["posts"])+""")
91
92     :crown: SOTWbC (Spammer-of-the-week-by-chars): **@"""+sotwc["username"]+"""** ("""+str(sotwc["chars"])+""")
93
94     |Rank|Username|Posts|Chars|Chars/post|Posts:7-day-diff|Chars:7-day-diff|
95     |---:|----|---:|---:|---:|---:|---:|
96     """)+"\n"
97     rank = 0
98     for record in cur.fetchall():
99         # add/remove users to/from 2k+ posts club. The post count can decline e.g. if channels are deleted.
100         if record["id"] in config.club_ignored_uids:
101             continue
102
103         if record["posts"] >= 2000 and record["id"] not in config.club_banned_uids:
104             rank += 1
105             mm.add_user_to_team(config.club_team_id, record["id"])
106             mm.add_user_to_channel(config.club_id, record["id"])
107             mm.update_channel_members_scheme_roles(config.club_id, record["id"], {"scheme_user": True, "scheme_admin": True})
108         else:
109             mm.remove_user_from_channel(config.club_id, record["id"], exc=False)
110
111         # setrank based on post count
112         if rank == 1 and record["id"] not in config.club_banned_uids:
113             pbb[0] = {"Name": ":envelope::1st_place_medal: **``Top-user! ("+str(record["posts"])+" posts)``**", "UserIDs": [record["id"]]}
114             msg += "|"+str(rank)+" ("+str(last_week_post_pos.index(record["id"])+1)+")|**``"+record["username"]+"``**|"+str(record["posts"])+"|"+str(record["chars"])+"|"+str(round(record["chars"]/record["posts"]))+"|"+str(record["posts"]-last_week_post_statsres[record["id"]][0])+"|"+str(record["chars"]-last_week_post_statsres[record["id"]][1])+"|\n"
115
116         elif rank == 2 and record["id"] not in config.club_banned_uids:
117             pbb[1] = {"Name": ":envelope::2nd_place_medal: **``Top-user! ("+str(record["posts"])+" posts)``**", "UserIDs": [record["id"]]}
118             msg += "|"+str(rank)+" ("+str(last_week_post_pos.index(record["id"])+1)+")|**``"+record["username"]+"``**|"+str(record["posts"])+"|"+str(record["chars"])+"|"+str(round(record["chars"]/record["posts"]))+"|"+str(record["posts"]-last_week_post_statsres[record["id"]][0])+"|"+str(record["chars"]-last_week_post_statsres[record["id"]][1])+"|\n"
119
120         elif rank == 3 and record["id"] not in config.club_banned_uids:
121             pbb[2] = {"Name": ":envelope::3rd_place_medal: **``Top-user! ("+str(record["posts"])+" posts)``**", "UserIDs": [record["id"]]}
122             msg += "|"+str(rank)+" ("+str(last_week_post_pos.index(record["id"])+1)+")|**``"+record["username"]+"``**|"+str(record["posts"])+"|"+str(record["chars"])+"|"+str(round(record["chars"]/record["posts"]))+"|"+str(record["posts"]-last_week_post_statsres[record["id"]][0])+"|"+str(record["chars"]-last_week_post_statsres[record["id"]][1])+"|\n"
123
124         elif record["posts"] >= 50000 and record["id"] not in config.club_banned_uids:
125             pbb[3]["UserIDs"].append(record["id"])
126             msg += "|"+str(rank)+" ("+str(last_week_post_pos.index(record["id"])+1)+")|**``"+record["username"]+"``**|"+str(record["posts"])+"|"+str(record["chars"])+"|"+str(round(record["chars"]/record["posts"]))+"|"+str(record["posts"]-last_week_post_statsres[record["id"]][0])+"|"+str(record["chars"]-last_week_post_statsres[record["id"]][1])+"|\n"
127
128         elif record["posts"] >= 20000 and record["id"] not in config.club_banned_uids:
129             pbb[4]["UserIDs"].append(record["id"])
130             msg += "|"+str(rank)+" ("+str(last_week_post_pos.index(record["id"])+1)+")|**``"+record["username"]+"``**|"+str(record["posts"])+"|"+str(record["chars"])+"|"+str(round(record["chars"]/record["posts"]))+"|"+str(record["posts"]-last_week_post_statsres[record["id"]][0])+"|"+str(record["chars"]-last_week_post_statsres[record["id"]][1])+"|\n"
131
132         elif record["posts"] >= 10000 and record["id"] not in config.club_banned_uids:
133             pbb[5]["UserIDs"].append(record["id"])
134             msg += "|"+str(rank)+" ("+str(last_week_post_pos.index(record["id"])+1)+")|**``"+record["username"]+"``**|"+str(record["posts"])+"|"+str(record["chars"])+"|"+str(round(record["chars"]/record["posts"]))+"|"+str(record["posts"]-last_week_post_statsres[record["id"]][0])+"|"+str(record["chars"]-last_week_post_statsres[record["id"]][1])+"|\n"
135
136         elif record["posts"] >= 5000 and record["id"] not in config.club_banned_uids:
137             pbb[6]["UserIDs"].append(record["id"])
138             msg += "|"+str(rank)+" ("+str(last_week_post_pos.index(record["id"])+1)+")|**``"+record["username"]+"``**|"+str(record["posts"])+"|"+str(record["chars"])+"|"+str(round(record["chars"]/record["posts"]))+"|"+str(record["posts"]-last_week_post_statsres[record["id"]][0])+"|"+str(record["chars"]-last_week_post_statsres[record["id"]][1])+"|\n"
139
140         elif record["posts"] >= 2000 and record["id"] not in config.club_banned_uids:
141             pbb[7]["UserIDs"].append(record["id"])
142             msg += "|"+str(rank)+" ("+str(last_week_post_pos.index(record["id"])+1)+")|**``"+record["username"]+"``**|"+str(record["posts"])+"|"+str(record["chars"])+"|"+str(round(record["chars"]/record["posts"]))+"|"+str(record["posts"]-last_week_post_statsres[record["id"]][0])+"|"+str(record["chars"]-last_week_post_statsres[record["id"]][1])+"|\n"
143
144         elif record["posts"] >= 1000:
145             pbb[8]["UserIDs"].append(record["id"])
146         elif record["posts"] >= 500:
147             pbb[9]["UserIDs"].append(record["id"])
148         elif record["posts"] >= 200:
149             pbb[10]["UserIDs"].append(record["id"])
150         elif record["posts"] >= 100:
151             pbb[11]["UserIDs"].append(record["id"])
152         elif record["posts"] >= 50:
153             pbb[12]["UserIDs"].append(record["id"])
154         elif record["posts"] >= 10:
155             pbb[13]["UserIDs"].append(record["id"])
156         elif record["posts"] >= 1:
157             pbb[14]["UserIDs"].append(record["id"])
158
159     cfg["PluginSettings"]["Plugins"]["com.mattermost.custom-attributes"]["customattributes"].extend(pbb)
160
161
162 ###############################
163 # uid based badges (pre cmbb) #
164 ###############################
165 for ubb_def in config.uid_based_bagdes_pre:
166     cfg["PluginSettings"]["Plugins"]["com.mattermost.custom-attributes"]["customattributes"].append({"Name": ubb_def[0], "UserIDs": ubb_def[1]})
167
168
169 ###################################
170 # channel-membership based badges #
171 ###################################
172 for cmbb_def in config.channel_membership_based_bagdes:
173     uids_in_channel = {u["user_id"] for u in mm.get_channel_members(cmbb_def[1])}
174     uids_not_in_channel = set()
175     if cmbb_def[2]:
176         uids_not_in_channel = {u["user_id"] for u in mm.get_channel_members(cmbb_def[2])}
177
178     uids = uids_in_channel - uids_not_in_channel - set(cmbb_def[3])
179     cfg["PluginSettings"]["Plugins"]["com.mattermost.custom-attributes"]["customattributes"].append({"Name": cmbb_def[0], "UserIDs": list(uids)})
180
181
182 ################################
183 # uid based badges (post cmbb) #
184 ################################
185 for ubb_def in config.uid_based_bagdes_post:
186     cfg["PluginSettings"]["Plugins"]["com.mattermost.custom-attributes"]["customattributes"].append({"Name": ubb_def[0], "UserIDs": ubb_def[1]})
187
188
189 ########################
190 # set mm-server-config #
191 ########################
192 mm._put("/v4/config", data=cfg)
193
194 # post 2k+posts stats to 2k+posts club channel.
195 if hasattr(config, "dbconnstring") and hasattr(config, "club_team_id") and hasattr(config, "club_id") :
196     mm.create_post(config.club_id, msg)
197
198 mm.logout()