linkToPDF2.py 18.4 KB
Newer Older
Dominik Woiwode's avatar
Dominik Woiwode committed
1
2
3
import datetime
import hashlib
import os
Dominik Woiwode's avatar
Dominik Woiwode committed
4
5
6
7
8
9
import smtplib
from dataclasses import dataclass
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
Dominik Woiwode's avatar
Dominik Woiwode committed
10
from enum import Enum
Dominik Woiwode's avatar
Dominik Woiwode committed
11
from pathlib import Path
Dominik Woiwode's avatar
Dominik Woiwode committed
12
from typing import Optional, Dict, List
Dominik Woiwode's avatar
Dominik Woiwode committed
13
14
15
16
17
18
19
20

import requests

NOT_APPROVED_SIGN = "*"
ATTACHEMENT_SIGN = "+"
FACHGRUPPENVOLLVERSAMMLUNG_SIGN = ">"

TEMPLATE_FOLDER = "templates"
Dominik Woiwode's avatar
Dominik Woiwode committed
21
DATA_FOLDER = "data"
Dominik Woiwode's avatar
Dominik Woiwode committed
22

Dominik Woiwode's avatar
Dominik Woiwode committed
23
24
25
26
27
DEFAULT_GREMIUM = None
LDAP_USER = None
LDAP_PASSWORD = None
LDAP_MAIL = None
LDAP_NAME = None
Dominik Woiwode's avatar
Dominik Woiwode committed
28

Dominik Woiwode's avatar
Dominik Woiwode committed
29
IGNORED_TOPS = ["Anwesende", "Ständiges", "Termine", "Mitteilungen/Verschiedenes", "Schluss"]
Jakob Marten's avatar
Jakob Marten committed
30
31

GIT_REPO = None
Dominik Woiwode's avatar
Dominik Woiwode committed
32
GIT_REPO_PATH = None
Jakob Marten's avatar
Jakob Marten committed
33
34
35
GIT_NAME = None
GIT_EMAIL = None

Dominik Woiwode's avatar
Dominik Woiwode committed
36
37
38
GRAV_PROTOCOL_PATH = "pages/fachrat/02.protokolle/"

git = None
Jakob Marten's avatar
Jakob Marten committed
39

Dominik Woiwode's avatar
Dominik Woiwode committed
40

Dominik Woiwode's avatar
Dominik Woiwode committed
41
42
43
@dataclass
class Gremium:
    name: str
Jakob Marten's avatar
Jakob Marten committed
44
    fullName: str
Dominik Woiwode's avatar
Dominik Woiwode committed
45
46
47
48
49
50
    template: str

    def fullTemplate(self):
        return str(Path(os.path.join(TEMPLATE_FOLDER, self.template)).absolute())


Jakob Marten's avatar
Jakob Marten committed
51
GREMIUM_FR = Gremium("finf", "Fachrat Informatik", "pandoc.finf.tex")
Dominik Woiwode's avatar
Dominik Woiwode committed
52
GREMIUM_FSR = Gremium("fsr", "Fachschaftsrat Elektrotechnik und Informatik", "pandoc.fsr.tex")
Dominik Woiwode's avatar
Dominik Woiwode committed
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


@dataclass
class MailParticipant:
    mail: str
    alias: str = None

    def __post_init__(self):
        self.alias = self.mail

    def __str__(self):
        return f"{self.alias} <{self.mail}>"

    @staticmethod
    def FR_INFO():
        return MailParticipant("fr-info@finf.uni-hannover.de", "FR-Info")

    @staticmethod
    def FR():
        return MailParticipant("fr@finf.uni-hannover.de", "Fachrat Informatik")


# Helper Functions
def sendFRMail(text: str, subject: str, sender: MailParticipant, receivers: List[MailParticipant],
               attachement: "BasePad" = None):
    mail = MIMEMultipart()
    mail['Content-transfer-encoding'] = '8bit'
    mail['From'] = sender.alias
    mail['Subject'] = subject
    receiveralias = ", ".join([r.alias for r in receivers])
    mail['To'] = receiveralias

    msg = MIMEText(text, "plain", "utf-8")
    mail.attach(msg)
    if attachement is not None:
        payload = MIMEBase('application', 'octet-stream')
        with open(attachement.compiledPath, "rb") as d:
            payload.set_payload(d.read())
        encoders.encode_base64(payload)
Jakob Marten's avatar
Jakob Marten committed
92
93
        payload.add_header('Content-Disposition',
                           f"attachment; filename={attachement.displayName}")
Dominik Woiwode's avatar
Dominik Woiwode committed
94
95
96
97
98
99
        mail.attach(payload)

    try:
        server = smtplib.SMTP("mail.finf.uni-hannover.de", 587)
        server.starttls()
        server.login(sender.mail, LDAP_PASSWORD)
Jakob Marten's avatar
Jakob Marten committed
100
101
        server.sendmail(
            sender.mail, [r.mail for r in receivers], mail.as_string())
Dominik Woiwode's avatar
Dominik Woiwode committed
102
103
104
        server.quit()
        print(f"Email \"{subject}\" an {receivers} erfolgreich versendet")
    except smtplib.SMTPException:
Jakob Marten's avatar
Jakob Marten committed
105
106
        print(
            f"Fehler beim Senden der Email \"{subject}\" von {sender} an {receivers}")
Dominik Woiwode's avatar
Dominik Woiwode committed
107
        raise
Dominik Woiwode's avatar
Dominik Woiwode committed
108
109


Jakob Marten's avatar
Jakob Marten committed
110
111
# === Git Helper ===
class GitHelper:
Dominik Woiwode's avatar
Dominik Woiwode committed
112
    def __init__(self, repository:str, repository_path:str):
Jakob Marten's avatar
Jakob Marten committed
113
        self.repository = repository
Dominik Woiwode's avatar
Dominik Woiwode committed
114
        self.repository_path = repository_path
Jakob Marten's avatar
Jakob Marten committed
115
116

    def clone(self):
Dominik Woiwode's avatar
Dominik Woiwode committed
117
        cmd = f'git clone {self.repository} {self.repository_path}'
Jakob Marten's avatar
Jakob Marten committed
118
119
        os.system(cmd)

120
    def forcePull(self):
Dominik Woiwode's avatar
Dominik Woiwode committed
121
        cmd = f'git -C {self.repository_path} fetch origin master'
122
        os.system(cmd)
Dominik Woiwode's avatar
Dominik Woiwode committed
123
        cmd = f'git -C {self.repository_path} reset --hard origin/master'
Jakob Marten's avatar
Jakob Marten committed
124
125
126
        os.system(cmd)

    def update(self):
Dominik Woiwode's avatar
Dominik Woiwode committed
127
        if os.path.exists(self.repository_path + "/.git"):
128
            self.forcePull()
Jakob Marten's avatar
Jakob Marten committed
129
130
131
132
        else:
            self.clone()

    def push(self):
Dominik Woiwode's avatar
Dominik Woiwode committed
133
        cmd = f'git -C {self.repository_path} push origin master'
Jakob Marten's avatar
Jakob Marten committed
134
135
        os.system(cmd)

Dominik Woiwode's avatar
Dominik Woiwode committed
136
137
    def add(self, file: str):
        cmd = f'git -C {self.repository_path} add {file}'
Jakob Marten's avatar
Jakob Marten committed
138
139
        os.system(cmd)

Dominik Woiwode's avatar
Dominik Woiwode committed
140
141
    def commit(self, msg: str):
        cmd = f'git -C {self.repository_path} commit -m \"{msg}\"'
Jakob Marten's avatar
Jakob Marten committed
142
143
144
        os.system(cmd)

    def config(self, email, name):
Dominik Woiwode's avatar
Dominik Woiwode committed
145
        cmd = f'git -C {self.repository_path} config user.name {name}'
Jakob Marten's avatar
Jakob Marten committed
146
        os.system(cmd)
Dominik Woiwode's avatar
Dominik Woiwode committed
147
        cmd = f'git -C {self.repository_path} config user.email {email}'
Jakob Marten's avatar
Jakob Marten committed
148
149
150
        os.system(cmd)


Dominik Woiwode's avatar
Dominik Woiwode committed
151
152
153
class SemesterPart(Enum):
    Summer = "Sommersemester"
    Winter = "Wintersemester"
Jakob Marten's avatar
Jakob Marten committed
154

Dominik Woiwode's avatar
Dominik Woiwode committed
155
156
157
158
    def short(self):
        if self == SemesterPart.Summer:
            return "SS"
        return "WS"
Jakob Marten's avatar
Jakob Marten committed
159
160


Dominik Woiwode's avatar
Dominik Woiwode committed
161
162
163
164
@dataclass(unsafe_hash=True)
class Semester:
    year: int
    part: SemesterPart
Jakob Marten's avatar
Jakob Marten committed
165

Dominik Woiwode's avatar
Dominik Woiwode committed
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
    def __post_init__(self):
        self.displayName = f"{self.part.value} {self.year}"
        self.gravPath = os.path.join(GIT_REPO_PATH, GRAV_PROTOCOL_PATH,
                                     self._gravName(), "protocol_semester.de.md")

    def _gravName(self):
        return f"{self.year - 2000}{self.part.short()}"

    @classmethod
    def fromDate(cls, date: datetime.datetime) -> "Semester":
        if 4 <= date.month < 10:
            # Summer
            return Semester(date.year, SemesterPart.Summer)
        elif date.month >= 10:
            # Winter
            return Semester(date.year, SemesterPart.Winter)
        else:
            # Winter
            return Semester(date.year - 1, SemesterPart.Winter)
Jakob Marten's avatar
Jakob Marten committed
185
186
187

    def uploadToGrav(self):
        if os.path.exists(self.gravPath):
188
            return
Jakob Marten's avatar
Jakob Marten committed
189

Dominik Woiwode's avatar
Dominik Woiwode committed
190
191
192
        os.makedirs(str(Path(self.gravPath).parent), exist_ok=True)
        with open(self.gravPath, "w") as d:
            d.write(f"---\ntitle: {self.displayName}\n---")
Jakob Marten's avatar
Jakob Marten committed
193

Dominik Woiwode's avatar
Dominik Woiwode committed
194
195
196
        git.add(GRAV_PROTOCOL_PATH)
        git.commit(f"Added {self.part.value} {self.year}")
        git.push()
Jakob Marten's avatar
Jakob Marten committed
197
198


Dominik Woiwode's avatar
Dominik Woiwode committed
199
# === Source Types ===
Dominik Woiwode's avatar
Dominik Woiwode committed
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
class SourceTypes:
    def __init__(self, url: str):
        self.url: str = url

    def __repr__(self):
        return f"{self.__class__.__name__}({self.url})"

    def retrieveContent(self):
        raise NotImplementedError()


class Etherpad(SourceTypes):
    def retrieveContent(self):
        url = f"{self.url}.txt"
        response = requests.get(url)
        return response.content.decode("utf-8")


class CodiMD(SourceTypes):
    def retrieveContent(self):
        url = f"{self.url}/download"
        response = requests.get(url)
        return response.content.decode("utf-8")


class LocalCache(SourceTypes):
    def retrieveContent(self):
        with open(self.url, "r", encoding="utf-8") as d:
            return d.read()


# === Pad Types ===
class BasePad:
Dominik Woiwode's avatar
Dominik Woiwode committed
233
    def __init__(self, source: SourceTypes, *_, displayName: str = None, rawPath=None, **kwargs):
Dominik Woiwode's avatar
Dominik Woiwode committed
234
235
236
        self.source = source
        self.metadata = kwargs
        self.rawPath = rawPath or hashlib.md5(source.url.encode("utf-8"))
Dominik Woiwode's avatar
Dominik Woiwode committed
237
238
        self.displayName = displayName or self.DEFAULT_DISPLAY_NAME()
        self.compiledPath = None
Jakob Marten's avatar
Jakob Marten committed
239
        self.folder = ""
Dominik Woiwode's avatar
Dominik Woiwode committed
240
241
242
243

    def __repr__(self):
        return f"{self.__class__.__name__}({self.source})"

Dominik Woiwode's avatar
Dominik Woiwode committed
244
245
246
247
248
249
250
251
252
253
254
255
    def DEFAULT_DISPLAY_NAME(self):
        return self.source.url

    def DEFAULT_RAW_PATH(self):
        return os.path.join(DATA_FOLDER, "raw", f"{self.displayName}.md")

    def DEFAULT_COMPILED_PATH(self):
        return os.path.join(DATA_FOLDER, "result", f"{self.displayName}.pdf")

    def download(self, path=None, override=True):
        if path is None:
            path = self.DEFAULT_RAW_PATH()
Dominik Woiwode's avatar
Dominik Woiwode committed
256
257
258
        content = self.source.retrieveContent()
        if not override and os.path.exists(path):
            raise FileExistsError(f"{path} already exists!")
Jakob Marten's avatar
Jakob Marten committed
259
        os.makedirs(str(Path(path).parent), exist_ok=True)
Dominik Woiwode's avatar
Dominik Woiwode committed
260
261
        with open(path, "w", encoding="utf-8") as d:
            d.write(content)
Dominik Woiwode's avatar
Dominik Woiwode committed
262
        self.rawPath = path
Dominik Woiwode's avatar
Dominik Woiwode committed
263

Dominik Woiwode's avatar
Dominik Woiwode committed
264
265
266
    def compile(self, outFilePath: str = None, template: str = None) -> int:
        if outFilePath is None:
            outFilePath = self.DEFAULT_COMPILED_PATH()
Dominik Woiwode's avatar
Dominik Woiwode committed
267
268
        outPath = Path(outFilePath)
        os.makedirs(outPath.parent, exist_ok=True)
Jakob Marten's avatar
Jakob Marten committed
269
        metadataStr = " " + \
Dominik Woiwode's avatar
Dominik Woiwode committed
270
271
                      " ".join([f'-M {key}="{val}"' for key,
                                                        val in self.metadata.items()])
Dominik Woiwode's avatar
Dominik Woiwode committed
272
        templateStr = ""
Dominik Woiwode's avatar
Dominik Woiwode committed
273
274
275
276
277
278
279
280
281
        if template is None and hasattr(self, "gremium"):
            templateStr = f' --template="{getattr(self, "gremium").fullTemplate()}" '
        elif template != "":
            templateStr = f' --template="{template}" '
        cmd = f'pandoc "{self.rawPath}" {metadataStr}{templateStr}-o "{str(outPath.absolute())}"'
        ret = os.system(cmd)
        if ret == 0:
            self.compiledPath = outFilePath
        return ret
Dominik Woiwode's avatar
Dominik Woiwode committed
282
283


Dominik Woiwode's avatar
Dominik Woiwode committed
284

Dominik Woiwode's avatar
Dominik Woiwode committed
285
class ProtocolPad(BasePad):
Dominik Woiwode's avatar
Dominik Woiwode committed
286
    def __init__(self, source: SourceTypes, *_, date: datetime.datetime = None,
Dominik Woiwode's avatar
Dominik Woiwode committed
287
288
                 isFachgruppenvollversammlung: bool = False, isApproved: bool = False, gremium: Gremium = None):
        self.gremium = gremium or DEFAULT_GREMIUM
Dominik Woiwode's avatar
Dominik Woiwode committed
289
290
291
        self.date = date
        self.isApproved = isApproved
        self.isFachgruppenvollversammlung = isFachgruppenvollversammlung
Jakob Marten's avatar
Jakob Marten committed
292
        self.semester = None
Dominik Woiwode's avatar
Dominik Woiwode committed
293
        super().__init__(source)
Dominik Woiwode's avatar
Dominik Woiwode committed
294
295
296
297

    def __repr__(self):
        return super(ProtocolPad, self).__repr__()[:-1] + f", {self.date})"

Dominik Woiwode's avatar
Dominik Woiwode committed
298
    def DEFAULT_DISPLAY_NAME(self):
Dominik Woiwode's avatar
Dominik Woiwode committed
299
        return f"Protokoll {self.gremium.name} {self.date.strftime('%Y-%m-%d')}" + " - Fachgruppenvollversammlung" * self.isFachgruppenvollversammlung
Dominik Woiwode's avatar
Dominik Woiwode committed
300

Jakob Marten's avatar
Jakob Marten committed
301
    def DEFAULT_GRAV_PATH(self):
Dominik Woiwode's avatar
Dominik Woiwode committed
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
        return os.path.join(GIT_REPO_PATH, GRAV_PROTOCOL_PATH,
                            self.semester._gravName(),
                            self.date.strftime("%Y-%m-%d") + "-fgvv" * self.isFachgruppenvollversammlung,
                            "default.de.md")

    def parseTops(self):
        # TODO: better top filter?
        lines = self.source.retrieveContent().split("\n")
        # with open(self.rawPath, "r", encoding="utf-8") as f:
        #     lines = f.read().split("\n")
        tops = []
        for l in lines:
            # Change to regex?
            # import re
            # res = re.match("^## ([\w\d &!\"'§$%/\-+äöüß]+)\w*(\(\d\d:\d\d Uhr\))?", l)
            # if res is not None:
            #     top = res.group(1)

            if l.startswith("## "):
                top = l.strip("#").rsplit("(")[0].strip()
                if any(top in t or t in top for t in IGNORED_TOPS):
                    continue
                tops.append(top)
        return tops
Jakob Marten's avatar
Jakob Marten committed
326

Dominik Woiwode's avatar
Dominik Woiwode committed
327
    def sendMailAsUnapproved(self) -> bool:
Dominik Woiwode's avatar
Dominik Woiwode committed
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
        sender = MailParticipant(LDAP_MAIL, LDAP_NAME)
        receiver = [
            MailParticipant.FR()
        ]
        text = (f"Hallo zusammen,\n\n"
                f"anbei das vorläufige Protokoll der Fachrats-Sitzung vom {self.date.strftime('%d.%m.%Y')}.\n\n"
                f"Änderungswünsche bitte direkt an mich, bzw. mir kurz Bescheid geben, wenn ihr was im Pad geändert habt.\n\n"
                f"Viele Grüße\n"
                f"{LDAP_NAME}\n")
        subject = f"Vorläufiges Protokoll der FR-Sitzung vom {self.date.strftime('%d.%m.%Y')}"
        try:
            sendFRMail(text, subject, sender, receiver, attachement=self)
        except Exception:
            return False
        return True

    def sendMailAsApproved(self) -> bool:
        if not self.isApproved:
            print("Protocol is not approved yet!")
            raise PermissionError("Protocol is not approved yet!")
        sender = MailParticipant(LDAP_MAIL, LDAP_NAME)
        receiver = [
            MailParticipant.FR_INFO()
        ]
        text = (f"Hallo zusammen,\n\n"
                f"anbei das Protokoll der Fachrats-Sitzung vom {self.date.strftime('%d.%m.%Y')}.\n\n"
                f"Alle Protokolle sind zu finden unter:\n"
                f"https://cloud.finf.uni-hannover.de/index.php/s/Erw9Cbta0PruqZI\n\n"
                f"Viele Grüße\n"
                f"{LDAP_NAME}\n")
        subject = f"Protokoll der FR-Sitzung vom {self.date.strftime('%d.%m.%Y')}"
        try:
            sendFRMail(text, subject, sender, receiver, attachement=self)
        except Exception:
            return False
        return True
Dominik Woiwode's avatar
Dominik Woiwode committed
364

Jakob Marten's avatar
Jakob Marten committed
365
    def uploadToCloud(self):
Dominik Woiwode's avatar
Dominik Woiwode committed
366
367
        pass

Jakob Marten's avatar
Jakob Marten committed
368
    def uploadToGrav(self):
Dominik Woiwode's avatar
Dominik Woiwode committed
369
        # Init semester
Jakob Marten's avatar
Jakob Marten committed
370
        # TODO: better file management
Jakob Marten's avatar
Jakob Marten committed
371
        self.semester.uploadToGrav()
Dominik Woiwode's avatar
Dominik Woiwode committed
372
373
374
375
        if not os.path.exists(self.rawPath):
            raise FileNotFoundError(f"{self.rawPath} doesn't exist")

        # TODO: move conversion to another method?
Jakob Marten's avatar
Jakob Marten committed
376
377
        with open(self.rawPath, "r", encoding="utf-8") as f:
            lines = f.read().split("\n")
Dominik Woiwode's avatar
Dominik Woiwode committed
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410

        # Tops
        tops = self.parseTops()
        tops_text = ", ".join(tops)

        # Header
        if self.isFachgruppenvollversammlung:
            name = "der Fachgruppenvollversammlung"
        else:
            name = f"des {self.gremium.fullName}"
        header = ("---\n"
                  f"title: Protokoll {name} am {self.date.strftime('%d.%m.%Y')}\n"
                  f"date: {self.date.strftime('%d.%m.%Y')}\n"
                  f"tops: {tops_text}\n"
                  "---\n\n"
                  "[MINITOC]\n\n")
        # Lines
        lines_new = [header]
        ignore = False
        for l in lines:
            if l.startswith("######"):  # tags 'fr'
                continue
            if l == "---":
                ignore = True
                continue
            if l == "...":
                ignore = False
                continue
            if ignore:
                continue
            lines_new.append(l)

        # Upload
Jakob Marten's avatar
Jakob Marten committed
411
412
413
        os.makedirs(str(Path(self.DEFAULT_GRAV_PATH()).parent), exist_ok=True)
        with open(self.DEFAULT_GRAV_PATH(), "w", encoding="utf-8") as f:
            f.write("\n".join(lines_new))
Dominik Woiwode's avatar
Dominik Woiwode committed
414
415
416
417

        git.add(GRAV_PROTOCOL_PATH)
        git.commit(f"Added protocol {self.displayName}")
        git.push()
Dominik Woiwode's avatar
Dominik Woiwode committed
418
419
420


class AttachementPad(BasePad):
Dominik Woiwode's avatar
Dominik Woiwode committed
421
422
423
424
425
426
    def __init__(self, source: SourceTypes, name: str, date: datetime.datetime = None, version=0, isApproved=False):
        super().__init__(source)
        self.name = name
        self.date = date
        self.version = version
        self.isApproved = isApproved
Dominik Woiwode's avatar
Dominik Woiwode committed
427
428
429
430
431
432


class PadCollection(BasePad):
    def __init__(self, source: SourceTypes):
        super().__init__(source)

Dominik Woiwode's avatar
Dominik Woiwode committed
433
434
435
    def DEFAULT_DISPLAY_NAME(self):
        return f"PadCollection"

Dominik Woiwode's avatar
Dominik Woiwode committed
436
    def getPads(self) -> Dict[str, List[BasePad]]:
Dominik Woiwode's avatar
Dominik Woiwode committed
437
438
439
        """
        Parsing the protocollink-Pad for urls.
        """
Dominik Woiwode's avatar
Dominik Woiwode committed
440
        pads = dict()
Jakob Marten's avatar
Jakob Marten committed
441
        semesters = dict()
Dominik Woiwode's avatar
Dominik Woiwode committed
442
        currentFolder = ""
Dominik Woiwode's avatar
Dominik Woiwode committed
443
        for line in self.source.retrieveContent().split("\n"):
Dominik Woiwode's avatar
Dominik Woiwode committed
444
445
446
            if line.startswith("# "):
                currentFolder = line.split("#")[1].strip()
                continue
Dominik Woiwode's avatar
Dominik Woiwode committed
447
448
449
            pad = self.parsePad(line)
            if pad is None:
                continue
Dominik Woiwode's avatar
Dominik Woiwode committed
450
451
            if currentFolder not in pads:
                pads[currentFolder] = list()
Dominik Woiwode's avatar
Dominik Woiwode committed
452
453
454
455
456
            if isinstance(pad, ProtocolPad) and pad.date is not None:
                semester = Semester.fromDate(pad.date)
                if semester not in semesters:
                    semesters[semester] = semester
                pad.semester = semester
Jakob Marten's avatar
Jakob Marten committed
457
            pad.folder = currentFolder
Dominik Woiwode's avatar
Dominik Woiwode committed
458
            pads[currentFolder].append(pad)
Dominik Woiwode's avatar
Dominik Woiwode committed
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490

        return pads

    def parsePad(self, line) -> Optional[BasePad]:
        url, *comment = line.split("#")
        if not url.strip():
            return None
        prefixes, url = url.split("https://")
        url = f"https://{url}"
        url = url.strip()

        if "/p/" in url:
            retrieveClass = Etherpad
        else:
            retrieveClass = CodiMD
        src = retrieveClass(url.strip())

        isAttachement = ATTACHEMENT_SIGN in prefixes
        isFachgrupenvollversammlung = FACHGRUPPENVOLLVERSAMMLUNG_SIGN in prefixes
        isApproved = NOT_APPROVED_SIGN not in prefixes

        kwargs = dict()
        if isAttachement:
            padType = AttachementPad
            kwargs["date"] = None
            kwargs["name"] = None
            kwargs["version"] = None
            kwargs["isApproved"] = isApproved
        else:
            padType = ProtocolPad
            kwargs["isApproved"] = isApproved
            try:
Jakob Marten's avatar
Jakob Marten committed
491
492
                date = datetime.datetime.strptime(
                    comment[0].strip(), "%d.%m.%Y")
Dominik Woiwode's avatar
Dominik Woiwode committed
493
494
495
496
497
498
499
500
501
502
            except Exception:
                dateStr = url.split("protokoll")[-1][:8]
                date = datetime.datetime.strptime(dateStr, "%Y%m%d")

            kwargs["date"] = date
            kwargs["isFachgruppenvollversammlung"] = isFachgrupenvollversammlung

        return padType(src, **kwargs)


Jakob Marten's avatar
Jakob Marten committed
503
def initGit():
Dominik Woiwode's avatar
Dominik Woiwode committed
504
505
    global git
    if any(o is None for o in [GIT_REPO, GIT_REPO_PATH, GIT_EMAIL, GIT_NAME]):
Jakob Marten's avatar
Jakob Marten committed
506
        raise RuntimeError("Git is not configured correctly")
Dominik Woiwode's avatar
Dominik Woiwode committed
507
508
509
    git = GitHelper(GIT_REPO, GIT_REPO_PATH)
    git.config(GIT_EMAIL, GIT_NAME)
    git.update()
Jakob Marten's avatar
Jakob Marten committed
510
511


Dominik Woiwode's avatar
Dominik Woiwode committed
512
513
514
if __name__ == '__main__':
    import argparse

Jakob Marten's avatar
Jakob Marten committed
515
516
    parser = argparse.ArgumentParser(
        description="Download and convert finf/fsr-protocols using pandoc")
Dominik Woiwode's avatar
Dominik Woiwode committed
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
    parser.add_argument("-urls", nargs="+", type=str, default=[])
    parser.add_argument("-pad", type=str, default=None)
    # parser.add_argument("--prefixes", type=str, default="",
    #                     help=f"Add additional information to pad:\n"
    #                          f"Not approved: {NOT_APPROVED_SIGN}\n"
    #                          f"Fachschaftenvollversammlung: {FACHSCHAFTENVERSAMMLUNG_SIGN}\n"
    #                          f"Attachement: {ATTACHEMENT_SIGN}\n")
    parser.add_argument("--finf", action="store_true")
    parser.add_argument("--topics", action="store_true")
    parser.add_argument("--fsr", action="store_true")
    parser.add_argument("--download", action="store_true")
    parser.add_argument("--ignoreOld", action="store_true")
    parser.add_argument("--compile", action="store_true")
    parser.add_argument("--attachementsOnly", action="store_true")
    parser.add_argument("--newOnly", action="store_true")
    parser.add_argument("--override", action="store_true")
    parser.add_argument("--mail", action="store_true")

    parsed = parser.parse_args()

    urls = parsed.urls
    if not urls and parsed.pad is None:
        parser.print_usage()
        exit()

    if parsed.finf and parsed.fsr:
        raise AttributeError("Cannot have --finf AND --fsr")

    if parsed.finf:
Dominik Woiwode's avatar
Dominik Woiwode committed
546
        DEFAULT_GREMIUM = GREMIUM_FR
Dominik Woiwode's avatar
Dominik Woiwode committed
547
    if parsed.fsr:
Dominik Woiwode's avatar
Dominik Woiwode committed
548
        DEFAULT_GREMIUM = GREMIUM_FSR
Dominik Woiwode's avatar
Dominik Woiwode committed
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570

    if parsed.override:
        OVERRIDE_ACCEPTED = True

    pads = getPadsFromCollectionPad(parsed.pad)
    pads += [PadOld.fromURL(url, prefixes=parsed.prefixes) for url in urls]

    if parsed.newOnly:
        pads = [pad for pad in pads if not pad.approved]
    if parsed.ignoreOld:
        pads = [pad for pad in pads if not pad.isOldPad()]
    if parsed.attachementsOnly:
        pads = [pad for pad in pads if pad.isAttachement()]

    if parsed.download:
        downloadPads(pads)

    # if parsed.topics:
    #     allPads(pads)

    if parsed.compile:
        compilePads(pads)