Compare commits

...

3 commits

Author SHA1 Message Date
d6a84c40a3
chore(extension): bump version number for release
Some checks failed
Build extension ZIP / Build extension (push) Successful in 1m20s
Publish docker image / Publish (push) Failing after 45s
2024-03-08 17:14:37 +00:00
0bee055a14
feat(extension): support fetching codes from reject via proxy 2024-03-08 17:13:55 +00:00
238961799d
feat(backend): add rejectdopamine proxy 2024-03-08 17:12:10 +00:00
9 changed files with 117 additions and 7 deletions

37
backend/aci/proxy.py Normal file
View file

@ -0,0 +1,37 @@
import aiohttp
from datetime import datetime
from fastapi import APIRouter
from .utils import format_checkin_date
router = APIRouter(prefix='/3p-proxy')
def reformat_reject_date(date: str):
return format_checkin_date(datetime.strptime(date, '%a %b %d %Y'))
@router.get('/reject')
async def reject_proxy(date: str, time: str, activity: str, space: str):
"""We proxy the rejectdopamine API to maintain user pivacy (the extension does not transmit user IP addresses to third-party services)"""
async with aiohttp.ClientSession(headers={'User-Agent': 'Mozilla 5.0 (compatible); aci-backend/1.0 (+https://git.ashhhleyyy.dev/ash/aci)'}) as session:
async with session.get('https://rejectdopamine.com/api/app/active/yrk/cs/1') as resp:
response = await resp.json()
activities = []
for session in response['sessions']:
if reformat_reject_date(session['startDate']) == date and time == f'{session["startTime"]} - {session["endTime"]}' and session['location'] in space:
# Likely a correct result, let's return it
return {
'date': date,
'time': time,
'space': space,
'activity': activity,
'codes': list(map(lambda c: {'code': f'{c["checkinCode"]:06}', 'score': 0}, session['codes']))
}
return {
'date': date,
'time': time,
'space': space,
'activity': activity,
'codes': [],
}

View file

@ -3,4 +3,7 @@ from datetime import datetime
def today() -> str:
now = datetime.now()
return f"{now.strftime('%A')} {now.day:02} {now.strftime('%B')}"
return format_checkin_date(now)
def format_checkin_date(dt: datetime):
return f"{dt.strftime('%A')} {dt.day:02} {dt.strftime('%B')}"

View file

@ -13,6 +13,7 @@ from aci.db import get_db
from aci.migrate import run_migrations
from aci.models import CodeSubmission
from aci import utils
from aci import proxy
app = FastAPI()
@ -82,6 +83,8 @@ def query_codes(date: str, time: str, activity: str, space: str, db: sqlite3.Cur
'codes': list(map(lambda c: {'code': c[0], 'score': c[1]}, code_scores.items()))
}
app.include_router(proxy.router)
if __name__ == '__main__':
run_migrations()
uvicorn.run(app, host='0.0.0.0')

View file

@ -2,7 +2,7 @@
{
"manifest_version": 2,
"name": "aci",
"version": "0.1.0",
"version": "0.2.0",
"description": "auto checkin",
"content_scripts":[
{
@ -11,6 +11,7 @@
}
],
"permissions": [
"storage",
"webRequest",
"*://aci-api.ashhhleyyy.dev/*",
"*://checkin.york.ac.uk/*"
@ -22,6 +23,9 @@
"browser_action": {
"default_popup": "src/popup.html"
},
"options_ui": {
"page": "src/config.html"
},
"browser_specific_settings": {
"gecko": {
"update_url": "https://git.ashhhleyyy.dev/ash/aci/raw/branch/main/addon_updates.json",

View file

@ -0,0 +1,12 @@
(async function() {
const rejectCheckbox = document.querySelector('#enable-reject');
chrome.storage.sync.get('enable_reject', (data) => {
rejectCheckbox.checked = data.enable_reject;
});
rejectCheckbox.addEventListener('change', async function() {
await chrome.storage.sync.set({
enable_reject: rejectCheckbox.checked,
});
});
rejectCheckbox.disabled = false;
})();

22
extension/src/config.html Normal file
View file

@ -0,0 +1,22 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Checkin Codes</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="ash.css">
<script src="config-page.js" defer></script>
</head>
<body>
<div class="page-container">
<main class="content" id="root">
<label>
<input id="enable-reject" type="checkbox" disabled>
Enable fetching codes from rejectdopamine.com (3rd party service)
</label>
</main>
</div>
</body>
</html>

View file

@ -1,2 +1,2 @@
this.SERVER_URL = 'https://aci-api.ashhhleyyy.dev';
//this.SERVER_URL = 'http://localhost:8000';
//this.SERVER_URL = 'https://aci-api.ashhhleyyy.dev';
this.SERVER_URL = 'http://localhost:8000';

View file

@ -1,4 +1,4 @@
(async function() {
chrome.storage.sync.get(['enable_reject'], async function(config) {
const root = document.querySelector('#root');
function codeTable(codes) {
@ -97,12 +97,39 @@
message(`Something went wrong: ${e}`);
console.error(e);
});
removeLoading();
if (!res.ok) {
removeLoading();
message('Server returned error code ' + res.status + ': ' + res.statusText, true);
return;
}
const activity = await res.json();
if (config.enable_reject) {
const rejectRes = await fetch(SERVER_URL + '/3p-proxy/reject?' + query).catch((e) => {
message(`Something went wrong: ${e}`);
console.error(e);
});
if (!rejectRes.ok) {
message('Warning: failed to fetch codes from reject');
} else {
const extraActivity = await rejectRes.json();
for (const code of extraActivity.codes) {
let found = false;
for (const code2 of activity.codes) {
if (code.code === code2.code) {
code2.score += code.score;
found = true;
break;
}
}
if (!found) {
activity.codes.push(code);
}
}
}
}
removeLoading();
if (activity.codes.length === 0) {
message('No codes are available right now :/');
} else {
@ -133,4 +160,4 @@
}
}
}
})();
});

View file

@ -13,10 +13,12 @@
dependencies = ps: with ps; [
fastapi
uvicorn
aoihttp
];
devDependencies = ps: with ps; [
fastapi
uvicorn
aiohttp
python-lsp-server
];
version = self.shortRev or self.dirtyShortDev or "dirty-inputs";