aboutsummaryrefslogtreecommitdiff
path: root/database/database.py
blob: 27a1af5358d435f80ab152c9c72e141b8e6e012c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
import sqlite3
import bcrypt
import time
from random import random, choice
from math import floor
from uuid import uuid4

connection = sqlite3.connect("./database.db")
cursor = connection.cursor()


def random_string():
    return str(
        floor(random() * 1e16)
    )  # 1e16 is wetenschappelijke notatie (1 * 10^16)


def repeat_action(action, name):
    def return_function():
        count = int(input(f"Hoeveel {name} wil je aanmaken? "))
        for i in range(count):
            action()
            print(f"{i+1}/{count} {name} toegevoegd!")
        print(f"{count} {name} toegevoegd!")

    return return_function


# dit is om dit script te organiseren
programma_acties = []


class programma_actie:
    def __init__(self, name, execute):
        self.name = name
        self.exec = execute


# initialiseer een nieuwe (lege) database
def init_db():
    commands_text = open("./init_db.sql").read()
    commands = commands_text.strip().split(
        "\n" * 2
    )  # python sqlite3 kan maar 1 "statement" per cursor.execute doen, en de statements zijn gescheden door witregels in ./init_db.sql
    for i, command in enumerate(commands):
        cursor.execute(command)
        print(f"SQL commando {i+1} van de {len(commands)} uitgevoerd...")
    print("Klaar!")


programma_acties.append(programma_actie("Maak tabellen aan", init_db))


def destroy_tables():
    for table_name in ["games", "users", "social"]:
        # format strings + sql is gevaarlijk vanwege sql injectie, maar omdat de invoer hier niet door de gebruiker aangepast kan worden is het semi-ok
        cursor.execute(f"drop table if exists {table_name}")
        print(f"Tabel \"{table_name}\" verwijderd!")


programma_acties.append(
    programma_actie("Verwijder alle tabellen", destroy_tables)
)


def user_amount():
    return len(cursor.execute("select user_id from users").fetchall())


# pak een willekeurige user_id uit de users tabel (gebruikt voor insert_random::games)
def random_player():
    return choice(cursor.execute("select user_id from users").fetchall())[0]


# class om alle functies die willekeurige data invoegen te organiseren (python heeft geen namespaces :( )
class insert_random:
    # omdat veel kolommen in onze database gebruikersinteracties opslaan laat ik ze hier leeg omdat ik geen tijd hem om gebruikersgedrag te simuleren.

    def __init__(self):
        pass

    def users(self):
        user_id = str(uuid4())
        username = random_string()
        email = f"{username}@example.com"
        password_hash = bcrypt.hashpw(
            random_string().encode("utf-8"), bcrypt.gensalt()
        )
        registered = int(time.time() * 1000)

        cursor.execute(
            "insert into users values (?, ?, ?, NULL, ?, ?, \"[]\", FALSE, \"user\", \"{}\", NULL, \"online\") ",
            (user_id, username, email, password_hash, registered)
        )

    def games(self):
        if user_amount() < 2:
            print("Er zijn niet genoeg gebruikers om spellen aan te maken!")
            return

        game_id = str(uuid4())
        timestamp = int(time.time() * 1000)

        cursor.execute(
            "insert into games values (?, NULL, NULL, ?, ?, NULL, ?, NULL, NULL, NULL, FALSE, \"in_progress\", \"default\") ",
            (game_id, random_player(), random_player(), timestamp)
        )

    def friends(self):
        users = list(
            rij[0]
            for rij in cursor.execute("select user_id from users").fetchall()
        )  # cursor.execute.fetchall() stuurt rijen altijd terug als tuples ookal vraag je 1 kolom op, dus dit zet het om naar een list van strings
        # maak een nieuwe rij aan voor elke gebruiker in tabel users als deze nog niet bestaat
        for user in users:
            if cursor.execute(
                "select user_id from social where user_id = ?", [user]
            ).fetchone():
                continue
            cursor.execute(
                "insert into social values (?, NULL, NULL, NULL)", [user]
            )


programma_acties.append(
    programma_actie(
        "Maak nepgebruikers aan",
        repeat_action(insert_random().users, "nepgebruikers")
    )
)
programma_acties.append(
    programma_actie(
        "Maak voorbeeld spellen aan",
        repeat_action(insert_random().games, "spellen")
    )
)
programma_acties.append(
    programma_actie(
        "Vul social tabel met gebruikers",
        insert_random().friends
    )
)


# Verifiëer een user_id of verkrijg een user_id uit een username
def resolve(resolveable):
    user_id = None
    user_id = user_id or cursor.execute(
        "select user_id from users where user_id = ?", [resolveable]
    ).fetchone()
    user_id = user_id or cursor.execute(
        "select user_id from users where username = ?", [resolveable]
    ).fetchone()
    # stuur de eerste kolom van de rij terug omdat het weer een tuple is >:(
    return user_id[0] if user_id else None


def edit_username():
    resolveable = input("Voer een gebruikers-id of gebruikersnaam in: ")
    user_id = resolve(resolveable)
    if not user_id:
        print(
            "Er is geen gebruiker met gebruikers-id of gebruikersnaam \"{resolveable}\""
        )
        return
    new_username = input("Voer een nieuwe gebruikersnaam in: ")
    cursor.execute(
        "update users set username = ? where user_id = ?",
        [new_username, user_id]
    )
    print("Nieuwe gebruikersnaam succesvol toegepast!")


programma_acties.append(
    programma_actie(
        "Pas de gebruikersnaam van een gebruiker aan", edit_username
    )
)


def delete_user():
    resolveable = input("Voer een gebruikers-id of gebruikersnaam in: ")
    user_id = resolve(resolveable)
    if not user_id:
        print(
            "Er is geen gebruiker met gebruikers-id of gebruikersnaam \"{resolveable}\""
        )
        return
    cursor.execute("delete from users where user_id = ?", [user_id])
    print("Gebruiker verwijderd!")


programma_acties.append(
    programma_actie("Verwijder een gebruiker", delete_user)
)


def mark_game_done():
    game_id = input("Voer een game-id in om als klaar te markeren: ")
    if not cursor.execute(
        "select game_id from games where game_id = ?", [game_id]
    ).fetchone():
        print("Kon geen spel vinden met die game_id!")
        return

    outcome = "w"
    starttime = cursor.execute(
        "select timestamp from games where game_id = ?", [game_id]
    ).fetchone()[0]
    duration = int(time.time() * 1000) - starttime
    cursor.execute(
        "update games set outcome = ?, duration = ?, status = \"finished\" where game_id = ?",
        [outcome, duration, game_id]
    )
    print("Spel gemarkeerd als afgelopen!")


programma_acties.append(
    programma_actie("Spel markeren als afgelopen", mark_game_done)
)


def delete_game():
    game_id = input("Voer een game-id in om te verwijderen: ")
    if not cursor.execute(
        "select game_id from games where game_id = ?", [game_id]
    ).fetchone():
        print("Kon geen spel vinden met die game_id!")
        return

    cursor.execute("delete from games where game_id = ?", [game_id])
    print("Spel verwijderd!")


programma_acties.append(programma_actie("Spel verwijderen", delete_game))


# maakt een vriendschap tussen 2 willekeurige user_id's
def make_friendship():
    # Dit is misschien de lelijkste functie die ik ooit heb geschreven, wees gewaarschuwd
    user_1 = random_player()
    user_2 = random_player()
    while user_1 == user_2:  # garandeer dat user_1 != user_2
        user_2 = random_player()

    # [v for v in ? if v] zorgt er voor dat lege list elementen worden verwijderd
    # .fetchone()[0] or "" is omdat deze kolommen ook NULL kunnen zijn, maar ik wil altijd een string
    # .split(",") is omdat het user_id's zijn die gescheden zijn door komma's
    user_1_friend_list = [
        v for v in (
            cursor.execute(
                "select friends from social where user_id = ?", [user_1]
            ).fetchone()[0] or ""
        ).split(",") if v
    ]
    user_2_friend_list = [
        v for v in (
            cursor.execute(
                "select friends from social where user_id = ?", [user_2]
            ).fetchone()[0] or ""
        ).split(",") if v
    ]

    user_1_friend_list.append(user_2)
    user_2_friend_list.append(user_1)

    cursor.execute(
        "update social set friends = ? where user_id = ?",
        [",".join(user_1_friend_list), user_1]
    )
    cursor.execute(
        "update social set friends = ? where user_id = ?",
        [",".join(user_2_friend_list), user_2]
    )

    print(f"Nieuwe vriendschap gemaakt tussen {user_1} en {user_2}")


programma_acties.append(programma_actie("Vriendschap maken", make_friendship))


def reset_friendlist():
    resolveable = input("Voer een gebruikers-id of gebruikersnaam in: ")
    user_id = resolve(resolveable)
    if not user_id:
        print(
            "Er is geen gebruiker met gebruikers-id of gebruikersnaam \"{resolveable}\""
        )
        return
    cursor.execute("delete from social where user_id = ?", [user_id])
    cursor.execute(
        "insert into social values (?, NULL, NULL, NULL)", [user_id]
    )
    print(f"Vriendenlijst van {user_id} geleegd!")


programma_acties.append(
    programma_actie("Vriendenlijst legen", reset_friendlist)
)

for table in ["users", "games", "social"]:
    programma_acties.append(
        programma_actie(
            f"Tabel '{table}' weergeven",
            lambda: print(cursor.execute(f"select * from {table}").fetchall())
        )
    )

programma_acties.append(
    programma_actie("Sla alle wijzigingen op", connection.commit)
)
programma_acties.append(programma_actie("Stop", exit))


def main():
    while True:
        # print witregels
        print("\n" * 2, end="")

        # print alle acties in programma_acties
        for i, actie in enumerate(programma_acties):
            print(f"#{i}: {actie.name}")

        # vraag om keuze
        keuze = int(input("Geef je keuze: "))
        print("\n", end="")

        # kijk of keuze bestaat
        if keuze > len(programma_acties) - 1:
            print("Die actie bestaat niet!")
            continue  # ga door naar de volgende iteratie van de while loop (voer keuze niet uit)

        # voer keuze uit
        programma_acties[keuze].exec()


if __name__ == "__main__":
    main()