From 9960989835e5a206947fbe5165a858ed04fd9af3 Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Wed, 25 Oct 2023 21:40:58 +0200
Subject: [PATCH 01/28] added verifier

---
 verifier.py | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 82 insertions(+)
 create mode 100644 verifier.py

diff --git a/verifier.py b/verifier.py
new file mode 100644
index 0000000..365ab83
--- /dev/null
+++ b/verifier.py
@@ -0,0 +1,82 @@
+import dateparser
+from datetime import date
+import random
+
+class Status(Enum):
+    PASS = 0
+    FAIL = 1
+    RATE_LIMIT = 2
+    COMPLETED = 3
+    NOT_LOGGED_IN = 4
+    UNKNOWN = 5
+    
+pending = random.shuffle(fetch_all_pending()) # returns a shuffled list
+
+# p consists of: id, timestamp, answer, status,
+
+for p in pending:
+    sub_id = p["id"] 
+    today = date.today().day  # returns the current day (number between 1 and 31)
+    year = date.today().year
+    solution = get_day_solution(today) # is equal to todays solution, if there is one. Is None otherwise.
+    if p["timestamp"]day != today:
+        update_status(sub_id,"INVALID")
+        continue
+    if solution:
+        if solution == p["answer"]:
+            update_status(sub_id,"CORRECT")
+        else:
+            update_status(sub_id,"INCORRECT")
+    else:
+        status, response = submit_answer(year, today, 1, p["answer"])
+        if status == Status.PASS:
+            update_status(sub_id,"CORRECT")
+            set_day_solution(today,p["answer"])
+        elif status == Status.FAIL:
+            update_status(sub_id,"INCORRECT")
+        elif status == Status.RATE_LIMIT:
+            sleep(response)            
+        
+def submit_answer(year, day, level, answer):
+    payload = {'level': level, 'answer': answer}
+    r = requests.post(
+        f'https://adventofcode.com/{year}/day/{int(day)}/answer',
+        data=payload,
+        headers={
+            "User-Agent": 'https://aoc.fg.informatik.uni-goettingen.de/ by fachgruppe@informatik.uni-goettingen.de',
+        }
+        cookies={'session': config.get_config()['session_cookie']}
+    )
+    response = r.text
+    if "That's the right answer" in response:
+        return Status.PASS, None
+    elif "That's not the right answer" in response:
+        return Status.FAIL, None
+    elif 'You gave an answer too recently' in response:
+        timeout = get_timeout(response)
+        return Status.RATE_LIMIT, timeout
+    elif 'Did you already complete it?' in response:
+        return Status.COMPLETED, None
+    elif '[Log In]' in response:
+        return Status.NOT_LOGGED_IN, None
+    else:
+        return Status.UNKNOWN, response 
+        
+def update_status(submission_id,status):
+    # changes the "STATUS" value of the submission by <SUBMISSION_ID> to <STATUS>
+def get_day_solution(day):
+    # tries to get solution for day <DAY> from solution database, returns None if there is none
+def fetch_all_pending():
+    # gets all database entries with the status "pending" as a list of dictionaries
+def set_day_solution(day,solution):
+    # changes the "SOLUTION" value of <DAY> to <SOLUTION> in the solution database
+    
+
+def get_timeout(resp):
+    return dateparser("now")-date.parser(" ".join(re.findall(r'\d+s|\d+m|\d+h',resp))).seconds   
+        
+        
+        
+
+        
+        
\ No newline at end of file
-- 
GitLab


From 23bc1296cccc2a402126ad218b089b6d4d3eba13 Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Thu, 26 Oct 2023 21:42:02 +0200
Subject: [PATCH 02/28] moved verifier to aocp

---
 verifier.py => aocp/verifier.py | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename verifier.py => aocp/verifier.py (100%)

diff --git a/verifier.py b/aocp/verifier.py
similarity index 100%
rename from verifier.py
rename to aocp/verifier.py
-- 
GitLab


From 8df759cb2ec0987a9f582a66bec327e8c85c7158 Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Thu, 26 Oct 2023 22:07:37 +0200
Subject: [PATCH 03/28] put into function

---
 aocp/verifier.py | 69 ++++++++++++++++++++++++++----------------------
 1 file changed, 38 insertions(+), 31 deletions(-)

diff --git a/aocp/verifier.py b/aocp/verifier.py
index 365ab83..e04df7b 100644
--- a/aocp/verifier.py
+++ b/aocp/verifier.py
@@ -1,6 +1,13 @@
 import dateparser
 from datetime import date
 import random
+from enum import Enum
+from flask import current_app
+import requests 
+from flask import app 
+
+def get_timeout(resp):
+    return dateparser("now")-date.parser(" ".join(re.findall(r'\d+s|\d+m|\d+h',resp))).seconds 
 
 class Status(Enum):
     PASS = 0
@@ -10,32 +17,32 @@ class Status(Enum):
     NOT_LOGGED_IN = 4
     UNKNOWN = 5
     
-pending = random.shuffle(fetch_all_pending()) # returns a shuffled list
+#pending = random.shuffle(fetch_all_pending()) # returns a shuffled list
 
 # p consists of: id, timestamp, answer, status,
-
-for p in pending:
-    sub_id = p["id"] 
-    today = date.today().day  # returns the current day (number between 1 and 31)
-    year = date.today().year
-    solution = get_day_solution(today) # is equal to todays solution, if there is one. Is None otherwise.
-    if p["timestamp"]day != today:
-        update_status(sub_id,"INVALID")
-        continue
-    if solution:
-        if solution == p["answer"]:
-            update_status(sub_id,"CORRECT")
+def verify():
+    for p in pending:
+        sub_id = p["id"] 
+        today = date.today().day  # returns the current day (number between 1 and 31)
+        year = date.today().year
+        solution = get_day_solution(today) # is equal to todays solution, if there is one. Is None otherwise.
+        if p["timestamp"].day != today:
+            update_status(sub_id,"INVALID")
+            continue
+        if solution:
+            if solution == p["answer"]:
+                update_status(sub_id,"CORRECT")
+            else:
+                update_status(sub_id,"INCORRECT")
         else:
-            update_status(sub_id,"INCORRECT")
-    else:
-        status, response = submit_answer(year, today, 1, p["answer"])
-        if status == Status.PASS:
-            update_status(sub_id,"CORRECT")
-            set_day_solution(today,p["answer"])
-        elif status == Status.FAIL:
-            update_status(sub_id,"INCORRECT")
-        elif status == Status.RATE_LIMIT:
-            sleep(response)            
+            status, response = submit_answer(year, today, 1, p["answer"])
+            if status == Status.PASS:
+                update_status(sub_id,"CORRECT")
+                set_day_solution(today,p["answer"])
+            elif status == Status.FAIL:
+                update_status(sub_id,"INCORRECT")
+            elif status == Status.RATE_LIMIT:
+                sleep(response)            
         
 def submit_answer(year, day, level, answer):
     payload = {'level': level, 'answer': answer}
@@ -44,8 +51,8 @@ def submit_answer(year, day, level, answer):
         data=payload,
         headers={
             "User-Agent": 'https://aoc.fg.informatik.uni-goettingen.de/ by fachgruppe@informatik.uni-goettingen.de',
-        }
-        cookies={'session': config.get_config()['session_cookie']}
+        },
+        cookies={'session': current_app.config["SECRET_AOC_COOKIE"]}
     )
     response = r.text
     if "That's the right answer" in response:
@@ -63,20 +70,20 @@ def submit_answer(year, day, level, answer):
         return Status.UNKNOWN, response 
         
 def update_status(submission_id,status):
+    pass
     # changes the "STATUS" value of the submission by <SUBMISSION_ID> to <STATUS>
 def get_day_solution(day):
+    pass
     # tries to get solution for day <DAY> from solution database, returns None if there is none
 def fetch_all_pending():
+    pass
     # gets all database entries with the status "pending" as a list of dictionaries
 def set_day_solution(day,solution):
+    pass
     # changes the "SOLUTION" value of <DAY> to <SOLUTION> in the solution database
     
 
-def get_timeout(resp):
-    return dateparser("now")-date.parser(" ".join(re.findall(r'\d+s|\d+m|\d+h',resp))).seconds   
-        
-        
-        
+
+submit_answer(2022,1,1,"30")
 
         
-        
\ No newline at end of file
-- 
GitLab


From 3d96e2b514c73ff88d7de5263bee539f94cc30fc Mon Sep 17 00:00:00 2001
From: Jake <j.vondoemming@stud.uni-goettingen.de>
Date: Thu, 26 Oct 2023 22:26:39 +0200
Subject: [PATCH 04/28] added missing requirements

---
 requirements.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/requirements.txt b/requirements.txt
index ac80811..d4bce02 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -7,3 +7,5 @@ Jinja2>=3.1.2
 MarkupSafe>=2.1.3
 packaging>=23.2
 Werkzeug>=3.0.0
+dateparser>=1.1.8
+requests>=2.31.0
-- 
GitLab


From a5c5f87931490696f6d90dc8263a667969751ec7 Mon Sep 17 00:00:00 2001
From: Jake <j.vondoemming@stud.uni-goettingen.de>
Date: Thu, 26 Oct 2023 22:27:28 +0200
Subject: [PATCH 05/28] added test-verifier command

---
 Makefile         |  4 ++++
 aocp/__init__.py |  4 ++++
 aocp/verifier.py | 12 +++++++++++-
 3 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index a117a6a..31e1b23 100644
--- a/Makefile
+++ b/Makefile
@@ -10,6 +10,10 @@ devserver: routes instance/aocp.sqlite
 routes:
 	flask --app aocp routes
 
+.PHONY: test-verifier
+test-verifier:
+	flask --app aocp test-verifier
+
 .PHONY: init-db
 init-db: instance/aocp.sqlite
 
diff --git a/aocp/__init__.py b/aocp/__init__.py
index dd91762..9e12b5e 100644
--- a/aocp/__init__.py
+++ b/aocp/__init__.py
@@ -1,5 +1,6 @@
 from . import db
 from . import auth
+from . import verifier
 
 import os
 import json
@@ -51,6 +52,9 @@ def create_app(test_config=None):
     # Initialize the database
     db.init_app(app)
 
+    # Initialize the verifier
+    verifier.init_app(app)
+
     # Register Blueprints (Paths)
     app.register_blueprint(auth.bp)
 
diff --git a/aocp/verifier.py b/aocp/verifier.py
index e04df7b..176a96b 100644
--- a/aocp/verifier.py
+++ b/aocp/verifier.py
@@ -6,6 +6,8 @@ from flask import current_app
 import requests 
 from flask import app 
 
+import click
+
 def get_timeout(resp):
     return dateparser("now")-date.parser(" ".join(re.findall(r'\d+s|\d+m|\d+h',resp))).seconds 
 
@@ -84,6 +86,14 @@ def set_day_solution(day,solution):
     
 
 
-submit_answer(2022,1,1,"30")
+#submit_answer(2022,1,1,"30")
 
         
+@click.command('test-verifier')
+def test_verifier_command():
+    """Execute the verifier once for testing."""
+    click.echo('Testing verifier...')
+    verify()
+
+def init_app(app):
+    app.cli.add_command(test_verifier_command)
-- 
GitLab


From 2ee79052e58da1af6a1096bb57a656bb9f7b337e Mon Sep 17 00:00:00 2001
From: Jake <j.vondoemming@stud.uni-goettingen.de>
Date: Thu, 26 Oct 2023 22:30:08 +0200
Subject: [PATCH 06/28] test-verifier is now in debug mode

---
 Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 31e1b23..6d5dbd7 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ routes:
 
 .PHONY: test-verifier
 test-verifier:
-	flask --app aocp test-verifier
+	flask --app aocp test-verifier --debug
 
 .PHONY: init-db
 init-db: instance/aocp.sqlite
-- 
GitLab


From 4a17a2e651de602dc1d6dfc92fe6f42abe2d585d Mon Sep 17 00:00:00 2001
From: Jake <j.vondoemming@stud.uni-goettingen.de>
Date: Thu, 26 Oct 2023 22:30:45 +0200
Subject: [PATCH 07/28] test-verifier is now in debug mode

---
 Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 6d5dbd7..3417683 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ routes:
 
 .PHONY: test-verifier
 test-verifier:
-	flask --app aocp test-verifier --debug
+	flask --app aocp --debug test-verifier
 
 .PHONY: init-db
 init-db: instance/aocp.sqlite
-- 
GitLab


From 15fce4bee791df656989492e891f8fbdc6490fff Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Thu, 26 Oct 2023 22:47:52 +0200
Subject: [PATCH 08/28] submit_solution can now be tested

---
 aocp/verifier.py | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/aocp/verifier.py b/aocp/verifier.py
index 176a96b..b2f0ec6 100644
--- a/aocp/verifier.py
+++ b/aocp/verifier.py
@@ -5,11 +5,12 @@ from enum import Enum
 from flask import current_app
 import requests 
 from flask import app 
+import re
 
 import click
 
 def get_timeout(resp):
-    return dateparser("now")-date.parser(" ".join(re.findall(r'\d+s|\d+m|\d+h',resp))).seconds 
+    return (dateparser.parse("now")-dateparser.parse(" ".join(re.findall(r'\d+s|\d+m|\d+h',resp)))).seconds 
 
 class Status(Enum):
     PASS = 0
@@ -19,10 +20,10 @@ class Status(Enum):
     NOT_LOGGED_IN = 4
     UNKNOWN = 5
     
-#pending = random.shuffle(fetch_all_pending()) # returns a shuffled list
 
 # p consists of: id, timestamp, answer, status,
 def verify():
+    pending = fetch_all_pending() # returns a shuffled list
     for p in pending:
         sub_id = p["id"] 
         today = date.today().day  # returns the current day (number between 1 and 31)
@@ -54,21 +55,36 @@ def submit_answer(year, day, level, answer):
         headers={
             "User-Agent": 'https://aoc.fg.informatik.uni-goettingen.de/ by fachgruppe@informatik.uni-goettingen.de',
         },
-        cookies={'session': current_app.config["SECRET_AOC_COOKIE"]}
+        cookies={'session': current_app.config["SESSION_COOKIE"]}
     )
     response = r.text
     if "That's the right answer" in response:
+        click.echo("CORRECT ANSWER")
+        
         return Status.PASS, None
     elif "That's not the right answer" in response:
+        click.echo("WROOOOONG")
+        
         return Status.FAIL, None
     elif 'You gave an answer too recently' in response:
         timeout = get_timeout(response)
+        click.echo("RATE LIMIT: "+str(timeout))
+        
         return Status.RATE_LIMIT, timeout
+
     elif 'Did you already complete it?' in response:
+        click.echo("ALREADY COMPLETED")
+        
         return Status.COMPLETED, None
+
     elif '[Log In]' in response:
+        click.echo("NOT LOGGED IN")
+        
         return Status.NOT_LOGGED_IN, None
+    
     else:
+        click.echo("HMMM- SUS")
+        
         return Status.UNKNOWN, response 
         
 def update_status(submission_id,status):
@@ -93,7 +109,7 @@ def set_day_solution(day,solution):
 def test_verifier_command():
     """Execute the verifier once for testing."""
     click.echo('Testing verifier...')
-    verify()
+    submit_answer(2022,1,1,"30")
 
 def init_app(app):
     app.cli.add_command(test_verifier_command)
-- 
GitLab


From e024ad5460f26f4319187e2aa553de266c1c7f3a Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Fri, 27 Oct 2023 00:27:00 +0200
Subject: [PATCH 09/28] started working on score.py

---
 score.py | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
 create mode 100644 score.py

diff --git a/score.py b/score.py
new file mode 100644
index 0000000..c9a94bc
--- /dev/null
+++ b/score.py
@@ -0,0 +1,15 @@
+def calculate_points(day, timedelta, is_first):
+    # get "base points" depending on day
+    base_points = 1+ day // 5 
+    bonus_time_points = timedelta // 8 
+    
+
+def is_first_solve(sub_id,day):
+    # query all "CORRECT"s of <DAY> and return the SUBMISSION ID first one
+    first = get_first(day)
+    return sub_id = first
+
+def get_datetime_info(timestamp):
+    day = timestamp.day()
+    aoc_hour = ( timestamp.hour -6 )% 24
+    return day, aoc_hour
-- 
GitLab


From e5226afdd92971b74c6aaadd219935180ed6a583 Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Fri, 27 Oct 2023 11:01:28 +0200
Subject: [PATCH 10/28] added proper timezone conversion

---
 score.py | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/score.py b/score.py
index c9a94bc..ffb2a33 100644
--- a/score.py
+++ b/score.py
@@ -1,3 +1,6 @@
+from datetime import datetime
+from zoneinfo import ZoneInfo
+
 def calculate_points(day, timedelta, is_first):
     # get "base points" depending on day
     base_points = 1+ day // 5 
@@ -10,6 +13,7 @@ def is_first_solve(sub_id,day):
     return sub_id = first
 
 def get_datetime_info(timestamp):
-    day = timestamp.day()
-    aoc_hour = ( timestamp.hour -6 )% 24
-    return day, aoc_hour
+    conv_time = timestamp.astimezone(ZoneInfo("EST"))
+    day = conv_time.day
+    hour = conv_time.hour
+    return day,hour
-- 
GitLab


From 147573649549c5ec1c4979dcfb41bf3b6d53562d Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Fri, 27 Oct 2023 11:06:53 +0200
Subject: [PATCH 11/28] calculate_points done

---
 score.py | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/score.py b/score.py
index ffb2a33..9a5d6d1 100644
--- a/score.py
+++ b/score.py
@@ -4,7 +4,19 @@ from zoneinfo import ZoneInfo
 def calculate_points(day, timedelta, is_first):
     # get "base points" depending on day
     base_points = 1+ day // 5 
-    bonus_time_points = timedelta // 8 
+    # all ranges inclusive
+    # 0-8: 2 points
+    # 8-16: 1 point
+    # 16-24: 0 points
+    bonus_time_points = (24-timedelta) // 8 
+    if is_first:
+        bonus_first = 1
+    else:
+        bonus_first = 0
+    score = base_points + bonus_time_points + bonus_first 
+    return score
+    
+         
     
 
 def is_first_solve(sub_id,day):
-- 
GitLab


From cc346947bd17088fe82b59ee98c7f991ff7e7460 Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Fri, 27 Oct 2023 11:08:30 +0200
Subject: [PATCH 12/28] added comments and missing function

---
 score.py | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/score.py b/score.py
index 9a5d6d1..4744461 100644
--- a/score.py
+++ b/score.py
@@ -3,29 +3,29 @@ from zoneinfo import ZoneInfo
 
 def calculate_points(day, timedelta, is_first):
     # get "base points" depending on day
-    base_points = 1+ day // 5 
-    # all ranges inclusive
+    base_points = 1+ day // 5  # base points increase by 1 every 5 days.
+    # bonus time points: (all ranges inclusive)
     # 0-8: 2 points
     # 8-16: 1 point
     # 16-24: 0 points
     bonus_time_points = (24-timedelta) // 8 
-    if is_first:
+    if is_first: # bonus point if person is first to solve on given day.
         bonus_first = 1
     else:
         bonus_first = 0
     score = base_points + bonus_time_points + bonus_first 
     return score
     
-         
-    
-
 def is_first_solve(sub_id,day):
-    # query all "CORRECT"s of <DAY> and return the SUBMISSION ID first one
     first = get_first(day)
     return sub_id = first
 
 def get_datetime_info(timestamp):
-    conv_time = timestamp.astimezone(ZoneInfo("EST"))
+    conv_time = timestamp.astimezone(ZoneInfo("EST")) # convert to EST time
     day = conv_time.day
     hour = conv_time.hour
     return day,hour
+
+def get_first(day):
+    pass
+    # query all "CORRECT"s of <DAY> and return the SUBMISSION ID first one
-- 
GitLab


From 91b9538d14658dfb549deefea5734cdd8ab7ece4 Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Mon, 30 Oct 2023 21:43:44 +0100
Subject: [PATCH 13/28] added comments

---
 score.py | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/score.py b/score.py
index 4744461..6016f98 100644
--- a/score.py
+++ b/score.py
@@ -2,6 +2,18 @@ from datetime import datetime
 from zoneinfo import ZoneInfo
 
 def calculate_points(day, timedelta, is_first):
+    """
+    Calculates the points based on day, time and if the solver was first.
+    
+    
+    Parameters:
+    day    -- Day of the solution.
+    timedelta -- Hour of the solution.
+    is_first -- Boolean (True if person was first to solve problem).
+    
+    Returns:
+    score -- the score
+    """
     # get "base points" depending on day
     base_points = 1+ day // 5  # base points increase by 1 every 5 days.
     # bonus time points: (all ranges inclusive)
-- 
GitLab


From 62085606044f58c6fde63e363dd91512b54a0e6a Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Mon, 30 Oct 2023 21:46:11 +0100
Subject: [PATCH 14/28] moved everything related to aoc to extra file

---
 aoc.py           | 61 ++++++++++++++++++++++++++++++++++++++++++++++++
 aocp/verifier.py | 55 -------------------------------------------
 2 files changed, 61 insertions(+), 55 deletions(-)
 create mode 100644 aoc.py

diff --git a/aoc.py b/aoc.py
new file mode 100644
index 0000000..002d635
--- /dev/null
+++ b/aoc.py
@@ -0,0 +1,61 @@
+import dateparser
+from datetime import date
+from enum import Enum
+from flask import current_app
+import requests 
+from flask import app 
+import re
+import click
+
+def get_timeout(resp):
+    return (dateparser.parse("now")-dateparser.parse(" ".join(re.findall(r'\d+s|\d+m|\d+h',resp)))).seconds 
+
+class Status(Enum):
+    PASS = 0
+    FAIL = 1
+    RATE_LIMIT = 2
+    COMPLETED = 3
+    NOT_LOGGED_IN = 4
+    UNKNOWN = 5
+    
+
+
+def submit_answer(year, day, level, answer):
+    payload = {'level': level, 'answer': answer}
+    r = requests.post(
+        f'https://adventofcode.com/{year}/day/{int(day)}/answer',
+        data=payload,
+        headers={
+            "User-Agent": 'https://aoc.fg.informatik.uni-goettingen.de/ by fachgruppe@informatik.uni-goettingen.de',
+        },
+        cookies={'session': current_app.config["SESSION_COOKIE"]}
+    )
+    response = r.text
+    if "That's the right answer" in response:
+        click.echo("CORRECT ANSWER")
+        
+        return Status.PASS, None
+    elif "That's not the right answer" in response:
+        click.echo("WROOOOONG")
+        
+        return Status.FAIL, None
+    elif 'You gave an answer too recently' in response:
+        timeout = get_timeout(response)
+        click.echo("RATE LIMIT: "+str(timeout))
+        
+        return Status.RATE_LIMIT, timeout
+
+    elif 'Did you already complete it?' in response:
+        click.echo("ALREADY COMPLETED")
+        
+        return Status.COMPLETED, None
+
+    elif '[Log In]' in response:
+        click.echo("NOT LOGGED IN")
+        
+        return Status.NOT_LOGGED_IN, None
+    
+    else:
+        click.echo("HMMM- SUS")
+        
+        return Status.UNKNOWN, response 
\ No newline at end of file
diff --git a/aocp/verifier.py b/aocp/verifier.py
index b2f0ec6..516919d 100644
--- a/aocp/verifier.py
+++ b/aocp/verifier.py
@@ -1,25 +1,9 @@
 import dateparser
 from datetime import date
-import random
-from enum import Enum
 from flask import current_app
-import requests 
 from flask import app 
-import re
-
 import click
 
-def get_timeout(resp):
-    return (dateparser.parse("now")-dateparser.parse(" ".join(re.findall(r'\d+s|\d+m|\d+h',resp)))).seconds 
-
-class Status(Enum):
-    PASS = 0
-    FAIL = 1
-    RATE_LIMIT = 2
-    COMPLETED = 3
-    NOT_LOGGED_IN = 4
-    UNKNOWN = 5
-    
 
 # p consists of: id, timestamp, answer, status,
 def verify():
@@ -47,45 +31,6 @@ def verify():
             elif status == Status.RATE_LIMIT:
                 sleep(response)            
         
-def submit_answer(year, day, level, answer):
-    payload = {'level': level, 'answer': answer}
-    r = requests.post(
-        f'https://adventofcode.com/{year}/day/{int(day)}/answer',
-        data=payload,
-        headers={
-            "User-Agent": 'https://aoc.fg.informatik.uni-goettingen.de/ by fachgruppe@informatik.uni-goettingen.de',
-        },
-        cookies={'session': current_app.config["SESSION_COOKIE"]}
-    )
-    response = r.text
-    if "That's the right answer" in response:
-        click.echo("CORRECT ANSWER")
-        
-        return Status.PASS, None
-    elif "That's not the right answer" in response:
-        click.echo("WROOOOONG")
-        
-        return Status.FAIL, None
-    elif 'You gave an answer too recently' in response:
-        timeout = get_timeout(response)
-        click.echo("RATE LIMIT: "+str(timeout))
-        
-        return Status.RATE_LIMIT, timeout
-
-    elif 'Did you already complete it?' in response:
-        click.echo("ALREADY COMPLETED")
-        
-        return Status.COMPLETED, None
-
-    elif '[Log In]' in response:
-        click.echo("NOT LOGGED IN")
-        
-        return Status.NOT_LOGGED_IN, None
-    
-    else:
-        click.echo("HMMM- SUS")
-        
-        return Status.UNKNOWN, response 
         
 def update_status(submission_id,status):
     pass
-- 
GitLab


From 54b1b945227470b633db8fa0dd4b6c227db32cb6 Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Sat, 11 Nov 2023 19:01:24 +0100
Subject: [PATCH 15/28] verifier works now probably

---
 aocp/verifier.py | 55 ++++++++++++++++++++++++++++--------------------
 1 file changed, 32 insertions(+), 23 deletions(-)

diff --git a/aocp/verifier.py b/aocp/verifier.py
index 516919d..680a7d2 100644
--- a/aocp/verifier.py
+++ b/aocp/verifier.py
@@ -3,33 +3,35 @@ from datetime import date
 from flask import current_app
 from flask import app 
 import click
+from . import db as database
+import time
+from . import aoc
+from typing import cast
 
 
 # p consists of: id, timestamp, answer, status,
 def verify():
-    pending = fetch_all_pending() # returns a shuffled list
-    for p in pending:
-        sub_id = p["id"] 
-        today = date.today().day  # returns the current day (number between 1 and 31)
-        year = date.today().year
-        solution = get_day_solution(today) # is equal to todays solution, if there is one. Is None otherwise.
-        if p["timestamp"].day != today:
-            update_status(sub_id,"INVALID")
-            continue
+    db = database.get_db()
+    pending = fetch_all_pending() # returns a dataframe
+    for index, p in pending.iterrows():
+        (uid,day,val) = cast(tuple,index)
+        year = 2022
+        solution = db.fetch_day_solution(day) # is equal to todays solution, if there is one. Is None otherwise.
         if solution:
-            if solution == p["answer"]:
-                update_status(sub_id,"CORRECT")
+            if solution == val:
+                db.update_submission_status(userid=uid,day=day,value=val,status="CORRECT")
             else:
-                update_status(sub_id,"INCORRECT")
+                db.update_submission_status(userid=uid,day=day,value=val,status="INCORRECT")
         else:
-            status, response = submit_answer(year, today, 1, p["answer"])
-            if status == Status.PASS:
-                update_status(sub_id,"CORRECT")
-                set_day_solution(today,p["answer"])
-            elif status == Status.FAIL:
-                update_status(sub_id,"INCORRECT")
-            elif status == Status.RATE_LIMIT:
-                sleep(response)            
+            status, timeout = aoc.submit_answer(year, day, 1, val)
+            if status == aoc.Status.PASS:
+                db.update_submission_status(userid=uid,day=day,value=val,status="CORRECT")
+                db.set_day_solution(day,val)
+            elif status == aoc.Status.FAIL:
+                db.update_submission_status(userid=uid,day=day,value=val,status="INCORRECT")
+            elif status == aoc.Status.RATE_LIMIT:
+                time.sleep(timeout)
+            
         
         
 def update_status(submission_id,status):
@@ -39,7 +41,7 @@ def get_day_solution(day):
     pass
     # tries to get solution for day <DAY> from solution database, returns None if there is none
 def fetch_all_pending():
-    pass
+    return database.get_db().fetch_submissions(status="PENDING")
     # gets all database entries with the status "pending" as a list of dictionaries
 def set_day_solution(day,solution):
     pass
@@ -54,7 +56,14 @@ def set_day_solution(day,solution):
 def test_verifier_command():
     """Execute the verifier once for testing."""
     click.echo('Testing verifier...')
-    submit_answer(2022,1,1,"30")
-
+    #submit_answer(2022,1,1,"30")
+    current_app.logger.debug(database.get_db().set_day_puzzle(day=3,puzzle=b'203nsk20'))
+    current_app.logger.debug(database.get_db().set_day_puzzle(day=7,puzzle=b'2138'))
+    current_app.logger.debug(database.get_db().set_day_puzzle(day=20,puzzle=b'abcabca'))
+    current_app.logger.debug(database.get_db().set_day_puzzle(day=1,puzzle=b'aksjndaks'))
+    current_app.logger.debug(database.get_db().set_day_solution(3,solution="123"))
+    current_app.logger.debug(database.get_db().set_day_solution(7,solution="13"))
+    current_app.logger.debug(database.get_db().set_day_solution(20,solution="abcabca"))
+    current_app.logger.debug(verify())
 def init_app(app):
     app.cli.add_command(test_verifier_command)
-- 
GitLab


From 4203bfa3f5e7d41ccf64e3c5bb53d7b67092a78d Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Sat, 11 Nov 2023 19:04:09 +0100
Subject: [PATCH 16/28] added download function

---
 aocp/aoc.py | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 94 insertions(+)
 create mode 100755 aocp/aoc.py

diff --git a/aocp/aoc.py b/aocp/aoc.py
new file mode 100755
index 0000000..c7bbdec
--- /dev/null
+++ b/aocp/aoc.py
@@ -0,0 +1,94 @@
+from typing import Literal
+import dateparser
+from datetime import date, datetime
+from enum import Enum
+from flask import current_app
+import requests 
+from flask import app 
+import re
+import click
+import requests
+
+current_year = date.today().year - 1
+
+def get_timeout(resp:str)->int: 
+    """
+    extracts a timeout from the response text.
+    returns the timeout in sec or 0 if parsing wasnt successful.
+    Example: get_timeout("please wait 20m") would return 1200.
+    """
+    current_time = datetime.now()
+    timeout = dateparser.parse(" ".join(re.findall(r'\d+s|\d+m|\d+h',resp)))
+    if timeout:
+        return (current_time - timeout).seconds
+    else:
+        return 0
+
+
+class Status(Enum):
+    PASS = 0
+    FAIL = 1
+    RATE_LIMIT = 2
+    COMPLETED = 3
+    NOT_LOGGED_IN = 4
+    UNKNOWN = 5
+    
+
+
+def submit_answer(year, day, level, answer)->tuple[Status,int|None]:
+    payload = {'level': level, 'answer': answer}
+    r = requests.post(
+        f'https://adventofcode.com/{year}/day/{int(day)}/answer',
+        data=payload,
+        headers={
+            "User-Agent": 'https://aoc.fg.informatik.uni-goettingen.de/ by fachgruppe@informatik.uni-goettingen.de',
+        },
+        cookies={'session': current_app.config["SESSION_COOKIE"]}
+    )
+    response = r.text
+    if "That's the right answer" in response:
+        #click.echo("CORRECT ANSWER")
+        
+        return Status.PASS, None
+    elif "That's not the right answer" in response:
+        #click.echo("WROOOOONG")
+        
+        return Status.FAIL, None
+    elif 'You gave an answer too recently' in response:
+        timeout = get_timeout(response)
+        click.echo("RATE LIMIT: "+str(timeout))
+        
+        return Status.RATE_LIMIT, timeout
+
+    elif 'Did you already complete it?' in response:
+        #click.echo("ALREADY COMPLETED")
+        
+        return Status.COMPLETED, None
+
+    elif '[Log In]' in response:
+        #click.echo("NOT LOGGED IN")
+        
+        return Status.NOT_LOGGED_IN, None
+    
+    else:
+        #click.echo("HMMM- SUS")
+        return Status.UNKNOWN, response 
+
+def get_puzzle(day:int):
+    puzzle = requests.get("https://adventofcode.com/"+str(current_year)+"/day/"+str(day)+"/input",allow_redirects=True, headers={
+            "User-Agent": 'https://aoc.fg.informatik.uni-goettingen.de/ by fachgruppe@informatik.uni-goettingen.de',
+        },cookies={'session': current_app.config["SESSION_COOKIE"]}).content
+    return puzzle
+
+
+@click.command('test-aoc-py')
+def test_aoc_py_command():
+    """testing commands"""
+    current_app.logger.info("testing get_puzzle")
+    current_app.logger.debug(get_puzzle(20))
+
+def init_app(app):
+    """
+    Gets called by __init__.py on initialization of the flask App.
+    """
+    app.cli.add_command(test_aoc_py_command)
-- 
GitLab


From ab279f28410e2460adc6403c426461f5309b1dc1 Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Sat, 11 Nov 2023 19:04:27 +0100
Subject: [PATCH 17/28] added things for testing purposes

---
 Makefile         |  5 +++++
 aocp/__init__.py |  7 +++++++
 temp.css         | 15 +++++++++++++++
 3 files changed, 27 insertions(+)
 create mode 100644 temp.css

diff --git a/Makefile b/Makefile
index 1734e6b..4f16d4d 100644
--- a/Makefile
+++ b/Makefile
@@ -23,3 +23,8 @@ init-db:
 reset-db:
 	$(RM) instance/aocp.sqlite
 	flask --app aocp init-db
+
+
+.PHONY: test-aoc-py
+test-aoc-py:
+	flask --app aocp --debug test-aoc-py
\ No newline at end of file
diff --git a/aocp/__init__.py b/aocp/__init__.py
index adaa288..195e0dd 100644
--- a/aocp/__init__.py
+++ b/aocp/__init__.py
@@ -1,6 +1,7 @@
 from . import db
 from . import auth
 from . import verifier
+from . import aoc
 
 import os
 import json
@@ -93,4 +94,10 @@ def create_app(test_config=None):
     auth.init_app(app)
     app.register_blueprint(auth.bp)
 
+    # Initialize aoc API
+    aoc.init_app(app)
+
+    # Initialize verifier
+    verifier.init_app(app)
+
     return app
diff --git a/temp.css b/temp.css
new file mode 100644
index 0000000..8d0a17e
--- /dev/null
+++ b/temp.css
@@ -0,0 +1,15 @@
+*{
+    color: #1d4289;
+    color: #00bf7d ;
+    color: #00b4c5 ;
+    color: #d80c18 ;
+    color: #8a0008 ;
+    color: #65942f ;
+    color: #056010 ;
+    color: #683abf ;
+    color: #2015d0 ;
+    color: #d54920 ;
+    color: #bc4498 ;
+    color: #9e6421 ;
+    color: #22808d ;
+}
\ No newline at end of file
-- 
GitLab


From 90a40bc8a2270d248242ddb430b0730362e2a4b8 Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Sat, 11 Nov 2023 19:10:30 +0100
Subject: [PATCH 18/28] =?UTF-8?q?m=C3=BCll=20entfernt.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 temp.css | 15 ---------------
 1 file changed, 15 deletions(-)
 delete mode 100644 temp.css

diff --git a/temp.css b/temp.css
deleted file mode 100644
index 8d0a17e..0000000
--- a/temp.css
+++ /dev/null
@@ -1,15 +0,0 @@
-*{
-    color: #1d4289;
-    color: #00bf7d ;
-    color: #00b4c5 ;
-    color: #d80c18 ;
-    color: #8a0008 ;
-    color: #65942f ;
-    color: #056010 ;
-    color: #683abf ;
-    color: #2015d0 ;
-    color: #d54920 ;
-    color: #bc4498 ;
-    color: #9e6421 ;
-    color: #22808d ;
-}
\ No newline at end of file
-- 
GitLab


From 4841c37e8e68fd018390d755cc3a26b4d18704a7 Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Sat, 11 Nov 2023 20:26:41 +0100
Subject: [PATCH 19/28] moved to aocp

---
 score.py => aocp/score.py | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename score.py => aocp/score.py (100%)

diff --git a/score.py b/aocp/score.py
similarity index 100%
rename from score.py
rename to aocp/score.py
-- 
GitLab


From 3a6897629ebe56d37510baf95f6972984248a997 Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Sat, 11 Nov 2023 20:37:45 +0100
Subject: [PATCH 20/28] added documentation

---
 aocp/aoc.py | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/aocp/aoc.py b/aocp/aoc.py
index c7bbdec..1f179e7 100755
--- a/aocp/aoc.py
+++ b/aocp/aoc.py
@@ -26,6 +26,10 @@ def get_timeout(resp:str)->int:
 
 
 class Status(Enum):
+    """
+    possible status after sending a request to aoc website.
+    gets returned by submit_answer
+    """
     PASS = 0
     FAIL = 1
     RATE_LIMIT = 2
@@ -35,7 +39,11 @@ class Status(Enum):
     
 
 
-def submit_answer(year, day, level, answer)->tuple[Status,int|None]:
+def submit_answer(year:int, day:int, level:int, answer:str)->tuple[Status,int|None]:
+    """
+    submits an answer to the aoc website for a given year and day.
+    returns a Status according to the result and, if there is a timeout, the timeout in seconds.
+    """
     payload = {'level': level, 'answer': answer}
     r = requests.post(
         f'https://adventofcode.com/{year}/day/{int(day)}/answer',
@@ -74,8 +82,11 @@ def submit_answer(year, day, level, answer)->tuple[Status,int|None]:
         #click.echo("HMMM- SUS")
         return Status.UNKNOWN, response 
 
-def get_puzzle(day:int):
-    puzzle = requests.get("https://adventofcode.com/"+str(current_year)+"/day/"+str(day)+"/input",allow_redirects=True, headers={
+def get_puzzle(year:int, day:int)->bytes:
+    """
+    returns the puzzle of a day as bytes.
+    """
+    puzzle = requests.get("https://adventofcode.com/"+str(year)+"/day/"+str(day)+"/input",allow_redirects=True, headers={
             "User-Agent": 'https://aoc.fg.informatik.uni-goettingen.de/ by fachgruppe@informatik.uni-goettingen.de',
         },cookies={'session': current_app.config["SESSION_COOKIE"]}).content
     return puzzle
-- 
GitLab


From b5b6297c24115750b038a77ed2d4daac0c9b9ae6 Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Sat, 11 Nov 2023 20:42:10 +0100
Subject: [PATCH 21/28] no int

---
 aocp/aoc.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/aocp/aoc.py b/aocp/aoc.py
index 1f179e7..a9dff99 100755
--- a/aocp/aoc.py
+++ b/aocp/aoc.py
@@ -46,7 +46,7 @@ def submit_answer(year:int, day:int, level:int, answer:str)->tuple[Status,int|No
     """
     payload = {'level': level, 'answer': answer}
     r = requests.post(
-        f'https://adventofcode.com/{year}/day/{int(day)}/answer',
+        f'https://adventofcode.com/{year}/day/{day}/answer',
         data=payload,
         headers={
             "User-Agent": 'https://aoc.fg.informatik.uni-goettingen.de/ by fachgruppe@informatik.uni-goettingen.de',
-- 
GitLab


From 76d2a879cba6cd27a4db8222bc12fca234c627bc Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Sat, 11 Nov 2023 20:44:35 +0100
Subject: [PATCH 22/28] removed dupliate file

---
 aoc.py | 61 ----------------------------------------------------------
 1 file changed, 61 deletions(-)
 delete mode 100644 aoc.py

diff --git a/aoc.py b/aoc.py
deleted file mode 100644
index 002d635..0000000
--- a/aoc.py
+++ /dev/null
@@ -1,61 +0,0 @@
-import dateparser
-from datetime import date
-from enum import Enum
-from flask import current_app
-import requests 
-from flask import app 
-import re
-import click
-
-def get_timeout(resp):
-    return (dateparser.parse("now")-dateparser.parse(" ".join(re.findall(r'\d+s|\d+m|\d+h',resp)))).seconds 
-
-class Status(Enum):
-    PASS = 0
-    FAIL = 1
-    RATE_LIMIT = 2
-    COMPLETED = 3
-    NOT_LOGGED_IN = 4
-    UNKNOWN = 5
-    
-
-
-def submit_answer(year, day, level, answer):
-    payload = {'level': level, 'answer': answer}
-    r = requests.post(
-        f'https://adventofcode.com/{year}/day/{int(day)}/answer',
-        data=payload,
-        headers={
-            "User-Agent": 'https://aoc.fg.informatik.uni-goettingen.de/ by fachgruppe@informatik.uni-goettingen.de',
-        },
-        cookies={'session': current_app.config["SESSION_COOKIE"]}
-    )
-    response = r.text
-    if "That's the right answer" in response:
-        click.echo("CORRECT ANSWER")
-        
-        return Status.PASS, None
-    elif "That's not the right answer" in response:
-        click.echo("WROOOOONG")
-        
-        return Status.FAIL, None
-    elif 'You gave an answer too recently' in response:
-        timeout = get_timeout(response)
-        click.echo("RATE LIMIT: "+str(timeout))
-        
-        return Status.RATE_LIMIT, timeout
-
-    elif 'Did you already complete it?' in response:
-        click.echo("ALREADY COMPLETED")
-        
-        return Status.COMPLETED, None
-
-    elif '[Log In]' in response:
-        click.echo("NOT LOGGED IN")
-        
-        return Status.NOT_LOGGED_IN, None
-    
-    else:
-        click.echo("HMMM- SUS")
-        
-        return Status.UNKNOWN, response 
\ No newline at end of file
-- 
GitLab


From 7ae09d1d2476f170d49729fb390321991aebbf1e Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Sat, 11 Nov 2023 20:55:03 +0100
Subject: [PATCH 23/28] added documentation, removed unnecessary functions

---
 aocp/score.py    |  1 +
 aocp/verifier.py | 35 +++++++++++++++++------------------
 2 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/aocp/score.py b/aocp/score.py
index 6016f98..09f2232 100644
--- a/aocp/score.py
+++ b/aocp/score.py
@@ -39,5 +39,6 @@ def get_datetime_info(timestamp):
     return day,hour
 
 def get_first(day):
+    
     pass
     # query all "CORRECT"s of <DAY> and return the SUBMISSION ID first one
diff --git a/aocp/verifier.py b/aocp/verifier.py
index 680a7d2..35ef56e 100644
--- a/aocp/verifier.py
+++ b/aocp/verifier.py
@@ -11,7 +11,15 @@ from typing import cast
 
 # p consists of: id, timestamp, answer, status,
 def verify():
-    db = database.get_db()
+    """
+    fetches all currently pending submissions from the database and checks 
+    if theyre correct. Checks if a solution already exists in the solution db
+    and uses it; makes a request to the aoc website otherwise.
+    if the submitted answer is correct the status of the submission in the db
+    gets updated accordingly.
+    if a ratelimit is returned this program will sleep for the remaining time.
+    """
+    db = database.get_db() # dataframe
     pending = fetch_all_pending() # returns a dataframe
     for index, p in pending.iterrows():
         (uid,day,val) = cast(tuple,index)
@@ -31,26 +39,17 @@ def verify():
                 db.update_submission_status(userid=uid,day=day,value=val,status="INCORRECT")
             elif status == aoc.Status.RATE_LIMIT:
                 time.sleep(timeout)
+            elif status == aoc.Status.NOT_LOGGED_IN:
+                current_app.logger.error("no/invalid aoc session cookie.")
+            elif status == aoc.Status.COMPLETED:
+                current_app.logger.warning("request made although puzzle already solved. not good.")
+            elif status == aoc.Status.UNKNOWN:
+                current_app.logger.warning("unknown status returned.")
             
         
-        
-def update_status(submission_id,status):
-    pass
-    # changes the "STATUS" value of the submission by <SUBMISSION_ID> to <STATUS>
-def get_day_solution(day):
-    pass
-    # tries to get solution for day <DAY> from solution database, returns None if there is none
 def fetch_all_pending():
-    return database.get_db().fetch_submissions(status="PENDING")
-    # gets all database entries with the status "pending" as a list of dictionaries
-def set_day_solution(day,solution):
-    pass
-    # changes the "SOLUTION" value of <DAY> to <SOLUTION> in the solution database
-    
-
-
-#submit_answer(2022,1,1,"30")
-
+    return database.get_db().fetch_submissions(status="PENDING").sample(frac=1)
+    # gets all database entries with the status "pending" as a dataframe
         
 @click.command('test-verifier')
 def test_verifier_command():
-- 
GitLab


From 42a4d1f80498eda66f251b33937c812ea8898485 Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Sat, 11 Nov 2023 20:58:09 +0100
Subject: [PATCH 24/28] using config now to determine year

---
 aocp/aoc.py      | 2 +-
 aocp/verifier.py | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/aocp/aoc.py b/aocp/aoc.py
index a9dff99..5ab961c 100755
--- a/aocp/aoc.py
+++ b/aocp/aoc.py
@@ -9,7 +9,7 @@ import re
 import click
 import requests
 
-current_year = date.today().year - 1
+current_year = current_app.config["YEAR"]
 
 def get_timeout(resp:str)->int: 
     """
diff --git a/aocp/verifier.py b/aocp/verifier.py
index 35ef56e..a9f314f 100644
--- a/aocp/verifier.py
+++ b/aocp/verifier.py
@@ -23,7 +23,7 @@ def verify():
     pending = fetch_all_pending() # returns a dataframe
     for index, p in pending.iterrows():
         (uid,day,val) = cast(tuple,index)
-        year = 2022
+        year = current_app.config["YEAR"]
         solution = db.fetch_day_solution(day) # is equal to todays solution, if there is one. Is None otherwise.
         if solution:
             if solution == val:
-- 
GitLab


From 237627cb4203a920ab161e40b139a712d5530f83 Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Sat, 11 Nov 2023 20:58:52 +0100
Subject: [PATCH 25/28] comment

---
 aocp/aoc.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/aocp/aoc.py b/aocp/aoc.py
index 5ab961c..6689b52 100755
--- a/aocp/aoc.py
+++ b/aocp/aoc.py
@@ -64,7 +64,7 @@ def submit_answer(year:int, day:int, level:int, answer:str)->tuple[Status,int|No
         return Status.FAIL, None
     elif 'You gave an answer too recently' in response:
         timeout = get_timeout(response)
-        click.echo("RATE LIMIT: "+str(timeout))
+        #click.echo("RATE LIMIT: "+str(timeout))
         
         return Status.RATE_LIMIT, timeout
 
-- 
GitLab


From 87b682fda96a4457ceb94a36f47cc453d8de82ca Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Sat, 11 Nov 2023 21:04:17 +0100
Subject: [PATCH 26/28] comments added

---
 aocp/score.py | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/aocp/score.py b/aocp/score.py
index 09f2232..8fdf747 100644
--- a/aocp/score.py
+++ b/aocp/score.py
@@ -1,7 +1,10 @@
 from datetime import datetime
 from zoneinfo import ZoneInfo
 
-def calculate_points(day, timedelta, is_first):
+# timedelta is hour after conversion!
+# return 0 points if not current day
+
+def calculate_points(day:int, timedelta:int, is_first:bool)->int:
     """
     Calculates the points based on day, time and if the solver was first.
     
@@ -28,17 +31,18 @@ def calculate_points(day, timedelta, is_first):
     score = base_points + bonus_time_points + bonus_first 
     return score
     
-def is_first_solve(sub_id,day):
+def is_first_solve(sub_id:tuple[int,int,int],day:int):
+    # incomplete function 
     first = get_first(day)
     return sub_id = first
 
-def get_datetime_info(timestamp):
+def get_datetime_info(timestamp:datetime):
     conv_time = timestamp.astimezone(ZoneInfo("EST")) # convert to EST time
     day = conv_time.day
     hour = conv_time.hour
     return day,hour
 
 def get_first(day):
-    
+    # missing function
     pass
     # query all "CORRECT"s of <DAY> and return the SUBMISSION ID first one
-- 
GitLab


From 895870298d3fc22b335aa4a5743b207ce1a787b3 Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Sat, 11 Nov 2023 21:04:56 +0100
Subject: [PATCH 27/28] oopsie

---
 aocp/score.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/aocp/score.py b/aocp/score.py
index 8fdf747..63b55b1 100644
--- a/aocp/score.py
+++ b/aocp/score.py
@@ -34,7 +34,7 @@ def calculate_points(day:int, timedelta:int, is_first:bool)->int:
 def is_first_solve(sub_id:tuple[int,int,int],day:int):
     # incomplete function 
     first = get_first(day)
-    return sub_id = first
+    return sub_id == first
 
 def get_datetime_info(timestamp:datetime):
     conv_time = timestamp.astimezone(ZoneInfo("EST")) # convert to EST time
-- 
GitLab


From 5d782925a83ced94a777b95482e80291d4f39d26 Mon Sep 17 00:00:00 2001
From: selina <selina.baehr@stud.uni-goettingen.de>
Date: Sat, 11 Nov 2023 21:08:17 +0100
Subject: [PATCH 28/28] vscodium happy now

---
 aocp/verifier.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/aocp/verifier.py b/aocp/verifier.py
index a9f314f..ba4fcf3 100644
--- a/aocp/verifier.py
+++ b/aocp/verifier.py
@@ -38,7 +38,8 @@ def verify():
             elif status == aoc.Status.FAIL:
                 db.update_submission_status(userid=uid,day=day,value=val,status="INCORRECT")
             elif status == aoc.Status.RATE_LIMIT:
-                time.sleep(timeout)
+                if timeout:
+                    time.sleep(timeout)
             elif status == aoc.Status.NOT_LOGGED_IN:
                 current_app.logger.error("no/invalid aoc session cookie.")
             elif status == aoc.Status.COMPLETED:
-- 
GitLab