Compare commits
2 commits
master
...
feature/gr
Author | SHA1 | Date | |
---|---|---|---|
|
f7fe427576 | ||
|
47a1b038a9 |
23
.github/workflows/backend.yml
vendored
|
@ -1,22 +1,27 @@
|
|||
name: Backend
|
||||
on: [push]
|
||||
env:
|
||||
PYTEST_ADDOPTS: "--color=yes"
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:10.8
|
||||
ports:
|
||||
- 5432:5432
|
||||
# needed because the postgres container does not provide a healthcheck
|
||||
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.10.4
|
||||
uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v1
|
||||
- name: Set up Python 3.9
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: 3.10.4
|
||||
python-version: 3.9
|
||||
- name: psycopg2 prerequisites
|
||||
run: sudo apt-get install python-dev libpq-dev
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r .github/workflows/requirements.txt
|
||||
pip install -r requirements.txt
|
||||
pip install pytest-django
|
||||
- name: Run tests
|
||||
working-directory: ./backend/
|
||||
run: pytest test.py
|
||||
run: python manage.py test
|
||||
|
|
71
.github/workflows/codeql-analysis.yml
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '26 12 * * 5'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'javascript', 'python', "typescript" ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
# Learn more:
|
||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
12
.github/workflows/frontend.yml
vendored
|
@ -2,15 +2,11 @@
|
|||
on: [push]
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
- name: Install deps
|
||||
working-directory: ./frontend
|
||||
run: npm install --immutable
|
||||
- uses: actions/checkout@v1
|
||||
- name: Install npm
|
||||
run: npm install --prefix frontend
|
||||
- name: Build app
|
||||
working-directory: ./frontend
|
||||
run: npm run build
|
||||
run: npm run build --prefix frontend
|
||||
|
|
12
.github/workflows/requirements.txt
vendored
|
@ -1,12 +0,0 @@
|
|||
beautifulsoup4
|
||||
bs4
|
||||
requests
|
||||
cryptography
|
||||
pytest
|
||||
pydantic~=1.9.0
|
||||
uvicorn~=0.17.5
|
||||
fastapi~=0.74.0
|
||||
starlette~=0.17.1
|
||||
lxml
|
||||
sty
|
||||
pytest-xdist
|
15
.gitignore
vendored
|
@ -8,7 +8,7 @@ __pycache__/
|
|||
*.code-workspace
|
||||
.idea/*
|
||||
.venv/*
|
||||
.DS_Store
|
||||
|
||||
### VisualStudioCode Patch ###
|
||||
# Ignore all local history of files
|
||||
.history
|
||||
|
@ -152,15 +152,4 @@ dmypy.json
|
|||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
node_modules/
|
||||
/tests/e2e/videos/
|
||||
/tests/e2e/screenshots/
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
node_modules/
|
33
Dockerfile
|
@ -1,29 +1,34 @@
|
|||
FROM nikolaik/python-nodejs:python3.10-nodejs16-bullseye
|
||||
FROM nikolaik/python-nodejs:python3.9-nodejs15
|
||||
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
|
||||
WORKDIR /src/frontend
|
||||
WORKDIR /src
|
||||
|
||||
COPY frontend/package-lock.json /src/frontend/package-lock.json
|
||||
COPY frontend/package.json /src/frontend/package.json
|
||||
COPY frontend/package-lock.json .
|
||||
COPY frontend/package*.json ./frontend/
|
||||
|
||||
RUN npm install
|
||||
|
||||
WORKDIR /src/backend
|
||||
COPY requirements.txt .
|
||||
|
||||
COPY backend/requirements.txt .
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
COPY app/* ./app/
|
||||
COPY app/API/* ./app/API/
|
||||
COPY app/migrations/* ./app/migrations/
|
||||
COPY frontend/* ./frontend/
|
||||
COPY frontend/src/* ./frontend/src/
|
||||
COPY frontend/public/* ./frontend/public/
|
||||
COPY frontend/tests/* ./frontend/tests/
|
||||
COPY backend/* ./backend/
|
||||
COPY backend/app/* ./backend/app/
|
||||
COPY backend/app/endpoints/* ./backend/app/endpoints/
|
||||
COPY backend/app/models/* ./backend/app/models/
|
||||
COPY frontend/migrations/* ./frontend/migrations/
|
||||
COPY frontend/static/frontend/* ./frontend/static/frontend/
|
||||
COPY frontend/static/frontend/css/* ./frontend/static/frontend/css/
|
||||
COPY frontend/static/frontend/images/* ./frontend/static/frontend/images/
|
||||
COPY frontend/templates/frontend/* ./frontend/templates/frontend/
|
||||
COPY wulkanowy/* ./wulkanowy/
|
||||
COPY manage.py .
|
||||
|
||||
RUN python manage.py makemigrations
|
||||
RUN python manage.py migrate
|
||||
|
||||
WORKDIR /src/frontend
|
||||
EXPOSE 8000
|
||||
|
||||
ENTRYPOINT [ "python3", "main", "0.0.0.0:8000"]
|
||||
ENTRYPOINT [ "python3", "manage.py", "runserver", "0.0.0.0:8000" ]
|
2
LICENSE
|
@ -186,7 +186,7 @@
|
|||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2022 Wulkanowy Web Team.
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
100
README.md
|
@ -1,49 +1,51 @@
|
|||
# Wulkanowy Web
|
||||
|
||||
🌋 Unofficial VULCAN UONET+ browser client for students and their parents
|
||||
|
||||
![GitHub Workflow Status](https://github.com/wulkanowy/wulkanowy-web/workflows/Python%20application/badge.svg)
|
||||
|
||||
## Join our Discord server!
|
||||
|
||||
[![Discord](https://discordapp.com/api/guilds/390889354199040011/widget.png?style=banner2)](https://discord.com/invite/vccAQBr)
|
||||
|
||||
# Development
|
||||
|
||||
## 1. Install dependencies
|
||||
|
||||
```sh
|
||||
cd backend
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
And in frontend:
|
||||
```sh
|
||||
cd frontend
|
||||
npm install
|
||||
```
|
||||
## 2. Start the server
|
||||
|
||||
```sh
|
||||
cd backend
|
||||
py -m main
|
||||
```
|
||||
And in frontend:
|
||||
```sh
|
||||
cd frontend
|
||||
npm run serve
|
||||
```
|
||||
|
||||
# Docker
|
||||
|
||||
With docker compose
|
||||
|
||||
```sh
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
Without docker compose
|
||||
|
||||
```sh
|
||||
docker build -t wulkanowy/web .
|
||||
docker run -d -p 8000:8000 wulkanowy/web
|
||||
```
|
||||
# Wulkanowy Web
|
||||
|
||||
🌋 Unofficial VULCAN UONET+ browser client for students and their parents
|
||||
|
||||
![GitHub Workflow Status](https://github.com/wulkanowy/wulkanowy-web/workflows/Python%20application/badge.svg)
|
||||
|
||||
## Join our Discord server!
|
||||
|
||||
[![Discord](https://discordapp.com/api/guilds/390889354199040011/widget.png?style=banner2)](https://discord.com/invite/vccAQBr)
|
||||
|
||||
# Development
|
||||
|
||||
## 1. Install dependencies
|
||||
|
||||
```sh
|
||||
pip install -r requirements.txt
|
||||
npm i --prefix frontend
|
||||
```
|
||||
|
||||
## 2. Make migrations
|
||||
|
||||
```sh
|
||||
python manage.py makemigrations
|
||||
python manage.py migrate
|
||||
```
|
||||
|
||||
## 3. Start the server
|
||||
|
||||
```sh
|
||||
python manage.py runserver
|
||||
```
|
||||
And in frontend:
|
||||
```shell
|
||||
cd frontend
|
||||
npm run build
|
||||
```
|
||||
|
||||
# Docker
|
||||
|
||||
With docker compose
|
||||
|
||||
```sh
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
Without docker compose
|
||||
|
||||
```sh
|
||||
docker build -t wulkanowy/web .
|
||||
docker run -d -p 8000:8000 wulkanowy/web
|
||||
```
|
||||
|
|
15
app/API/attendance.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
import requests
|
||||
import json
|
||||
from .generate_cookies import autogenerate_cookies
|
||||
|
||||
def get_attendance(register_id, students, oun, s, date):
|
||||
cookies = autogenerate_cookies(students, s)
|
||||
|
||||
with open('app/API/headers.json') as f:
|
||||
headers = json.load(f)
|
||||
|
||||
attendance_lessons = requests.post(oun+'/FrekwencjaStatystykiPrzedmioty.mvc/Get', headers=headers, cookies=cookies)
|
||||
attendance_json_id = attendance_lessons.json()['data'][0]['Id']
|
||||
attendance = requests.post(oun+'/Frekwencja.mvc/Get', headers=headers, cookies=cookies, json={'idTypWpisuFrekwencji': attendance_json_id, 'data': date})
|
||||
|
||||
return [attendance.json(), attendance_lessons.json()]
|
37
app/API/dashboard.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
import json
|
||||
import requests
|
||||
import re
|
||||
from bs4 import BeautifulSoup
|
||||
from .generate_cookies import autogenerate_cookies
|
||||
|
||||
def get_dashboard(register_id, students, s, diary_url, symbol):
|
||||
if diary_url != 'http://cufs.fakelog.tk/':
|
||||
diary_url = 'http://uonetplus.vulcan.net.pl/'
|
||||
else:
|
||||
diary_url = 'http://uonetplus.fakelog.tk/'
|
||||
|
||||
cookies = autogenerate_cookies(students, s)
|
||||
|
||||
with open('app/API/headers.json') as f:
|
||||
headers = json.load(f)
|
||||
|
||||
index = requests.get(f'{diary_url}{symbol}/Start.mvc/Index', headers=headers, cookies=cookies)
|
||||
permissions_value = re.search("permissions: '(.)*'", index.text)
|
||||
permissions_value = permissions_value.group()
|
||||
permissions_value = permissions_value.replace('permissions: ', '').replace("'", "")
|
||||
|
||||
permissions = {
|
||||
"permissions": permissions_value
|
||||
}
|
||||
|
||||
last_notes = requests.post(f'{diary_url}{symbol}/Start.mvc/GetLastNotes', headers=headers, cookies=cookies, json=permissions)
|
||||
free_days = requests.post(f'{diary_url}{symbol}/Start.mvc/GetFreeDays', headers=headers, cookies=cookies, json=permissions)
|
||||
lucky_number = requests.post(f'{diary_url}{symbol}/Start.mvc/GetKidsLuckyNumbers', headers=headers, cookies=cookies, json=permissions)
|
||||
|
||||
return_data = {
|
||||
"last_notes": last_notes.json(),
|
||||
"free_days": free_days.json(),
|
||||
"lucky_number": lucky_number.json()
|
||||
}
|
||||
|
||||
return return_data
|
13
app/API/exams.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
import json
|
||||
import requests
|
||||
from .generate_cookies import autogenerate_cookies
|
||||
|
||||
def get_exams(register_id, students, oun, s, date, school_year):
|
||||
cookies = autogenerate_cookies(students, s)
|
||||
|
||||
with open('app/API/headers.json') as f:
|
||||
headers = json.load(f)
|
||||
|
||||
exams = requests.post(oun+'/Sprawdziany.mvc/Get', headers=headers, cookies=cookies, json={'data': date, 'rokSzkolny': school_year})
|
||||
|
||||
return exams.json()
|
12
app/API/generate_cookies.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
import json
|
||||
|
||||
def autogenerate_cookies(students, s):
|
||||
cookies = s
|
||||
cookies.update({
|
||||
"biezacyRokSzkolny": f"{students['data'][0]['DziennikRokSzkolny']}",
|
||||
"idBiezacyDziennik": f"{students['data'][0]['IdDziennik']}",
|
||||
"idBiezacyDziennikPrzedszkole": f"{students['data'][0]['IdPrzedszkoleDziennik']}",
|
||||
"idBiezacyUczen": f"{students['data'][0]['IdUczen']}"
|
||||
})
|
||||
|
||||
return cookies
|
13
app/API/grades.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
import json
|
||||
import requests
|
||||
from .generate_cookies import autogenerate_cookies
|
||||
|
||||
def get_grades(register_id, students, oun, s):
|
||||
cookies = autogenerate_cookies(students, s)
|
||||
|
||||
with open('app/API/headers.json') as f:
|
||||
headers = json.load(f)
|
||||
|
||||
grades = requests.post(oun+'/Oceny.mvc/Get', headers=headers, cookies=cookies, json={'okres': register_id})
|
||||
|
||||
return grades.json()
|
6
app/API/headers.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"Accept-Encoding": "gzip, deflate",
|
||||
"Accept": "*/*",
|
||||
"Connection": "keep-alive",
|
||||
"User-Agent": "Wulkanowy-web :)"
|
||||
}
|
13
app/API/homeworks.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
import requests
|
||||
import json
|
||||
from .generate_cookies import autogenerate_cookies
|
||||
|
||||
def get_homeworks(register_id, students, oun, s, date, school_year):
|
||||
cookies = autogenerate_cookies(students, s)
|
||||
|
||||
with open('app/API/headers.json') as f:
|
||||
headers = json.load(f)
|
||||
|
||||
homeworks = requests.post(oun+'/Homework.mvc/Get', headers=headers, cookies=cookies, json={'schoolYear': school_year, 'date': date, 'statusFilter': '-1'})
|
||||
|
||||
return homeworks.json()
|
182
app/API/messages.py
Normal file
|
@ -0,0 +1,182 @@
|
|||
import requests
|
||||
import json
|
||||
import calendar
|
||||
import time
|
||||
import re
|
||||
from .generate_cookies import autogenerate_cookies
|
||||
|
||||
def get_received_messages(register_id, students, oun, s, date, school_year, symbol):
|
||||
with open('app/API/headers.json') as f:
|
||||
headers = json.load(f)
|
||||
|
||||
now = calendar.timegm(time.gmtime())
|
||||
|
||||
if oun == 'http://uonetplus-uczen.fakelog.tk/powiatwulkanowy/123458':
|
||||
received_messages = requests.get(f'http://uonetplus-uzytkownik.fakelog.tk/{symbol}/Wiadomosc.mvc/GetInboxMessages?_dc={now}&dataOd=&dataDo=&page=1&start=0&limit=25', headers=headers, cookies=s)
|
||||
else:
|
||||
received_messages = requests.get(f'https://uonetplus-uzytkownik.vulcan.net.pl/{symbol}/Wiadomosc.mvc/GetInboxMessages?_dc={now}&dataOd=&dataDo=&page=1&start=0&limit=25', headers=headers, cookies=s)
|
||||
|
||||
return received_messages.json()
|
||||
|
||||
def get_sent_messages(register_id, students, oun, s, date, school_year, symbol):
|
||||
with open('app/API/headers.json') as f:
|
||||
headers = json.load(f)
|
||||
|
||||
now = calendar.timegm(time.gmtime())
|
||||
|
||||
if oun == 'http://uonetplus-uczen.fakelog.tk/powiatwulkanowy/123458':
|
||||
sent_messages = requests.get(f'http://uonetplus-uzytkownik.fakelog.tk/{symbol}/Wiadomosc.mvc/GetInboxMessages?_dc={now}&dataOd=&dataDo=&page=1&start=0&limit=25', headers=headers, cookies=s)
|
||||
else:
|
||||
sent_messages = requests.get(f'https://uonetplus-uzytkownik.vulcan.net.pl/{symbol}/Wiadomosc.mvc/GetInboxMessages?_dc={now}&dataOd=&dataDo=&page=1&start=0&limit=25', headers=headers, cookies=s)
|
||||
|
||||
return sent_messages.json()
|
||||
|
||||
def get_deleted_messages(register_id, students, oun, s, date, school_year, symbol):
|
||||
with open('app/API/headers.json') as f:
|
||||
headers = json.load(f)
|
||||
|
||||
now = calendar.timegm(time.gmtime())
|
||||
|
||||
if oun == 'http://uonetplus-uczen.fakelog.tk/powiatwulkanowy/123458':
|
||||
deleted_messages = requests.get(f'http://uonetplus-uzytkownik.fakelog.tk/{symbol}/Wiadomosc.mvc/GetOutboxMessages?_dc={now}&dataOd=&dataDo=&page=1&start=0&limit=25', headers=headers, cookies=s)
|
||||
else:
|
||||
deleted_messages = requests.get(f'https://uonetplus-uzytkownik.vulcan.net.pl/{symbol}/Wiadomosc.mvc/GetOutboxMessages?_dc={now}&dataOd=&dataDo=&page=1&start=0&limit=25', headers=headers, cookies=s)
|
||||
|
||||
return deleted_messages.json()
|
||||
|
||||
def get_recipients(register_id, students, oun, s, date, school_year, symbol):
|
||||
with open('app/API/headers.json') as f:
|
||||
headers = json.load(f)
|
||||
|
||||
if oun == 'http://uonetplus-uczen.fakelog.tk/powiatwulkanowy/123458':
|
||||
link = f'http://uonetplus-uzytkownik.fakelog.tk/{symbol}'
|
||||
else:
|
||||
link = f'https://uonetplus-uzytkownik.vulcan.net.pl/{symbol}'
|
||||
|
||||
get_jednostki = requests.get(f'{link}/NowaWiadomosc.mvc/GetJednostkiUzytkownika', headers=headers, cookies=s)
|
||||
id_jednostka = get_jednostki.json()['data'][0]['IdJednostkaSprawozdawcza']
|
||||
data = {
|
||||
"paramsVo":{"IdJednostkaSprawozdawcza":id_jednostka, 'Rola': 2}
|
||||
}
|
||||
get_addressee = requests.post(f'{link}/Adresaci.mvc/GetAddressee', headers=headers, cookies=s, json=data)
|
||||
|
||||
return {'addressee': get_addressee.json(), 'unitId': id_jednostka}
|
||||
|
||||
def send_message(register_id, students, oun, s, date, school_year, symbol, send_data):
|
||||
with open('app/API/headers.json') as f:
|
||||
headers = json.load(f)
|
||||
|
||||
if oun == 'http://uonetplus-uczen.fakelog.tk/powiatwulkanowy/123458':
|
||||
link = f'http://uonetplus-uzytkownik.fakelog.tk/{symbol}'
|
||||
else:
|
||||
link = f'https://uonetplus-uzytkownik.vulcan.net.pl/{symbol}'
|
||||
|
||||
student_data = students['data'][0]['UczenNazwisko']+' '+students['data'][0]['UczenImie']
|
||||
|
||||
sess = requests.Session()
|
||||
|
||||
sess.cookies.update(s)
|
||||
sess.headers.update(headers)
|
||||
|
||||
index = sess.get(link)
|
||||
|
||||
antiForgeryToken = re.search("antiForgeryToken: '(.)*'", index.text)
|
||||
antiForgeryToken = antiForgeryToken.group()
|
||||
antiForgeryToken = antiForgeryToken.replace('antiForgeryToken: ', '').replace("'", "")
|
||||
|
||||
appGuid = re.search("appGuid: '(.)*'", index.text)
|
||||
appGuid = appGuid.group()
|
||||
appGuid = appGuid.replace('appGuid: ', '').replace("'", "")
|
||||
|
||||
sess.headers.update({
|
||||
'X-V-RequestVerificationToken': antiForgeryToken,
|
||||
'X-V-AppGuid': appGuid,
|
||||
'Content-Type': 'application/json',
|
||||
'TE': "Trailers"
|
||||
})
|
||||
|
||||
payload = {
|
||||
"incomming": {
|
||||
"Id": 0,
|
||||
"Nieprzeczytane": 0,
|
||||
"Przeczytane": 0,
|
||||
"Nieprzeczytana": False,
|
||||
"FolderWiadomosci": 0,
|
||||
"WiadomoscPowitalna": False,
|
||||
"Data": None,
|
||||
"Tresc": send_data['content'],
|
||||
"Temat": send_data['subject'],
|
||||
"IdWiadomosci": 0,
|
||||
"HasZalaczniki": False,
|
||||
"Zalaczniki": "",
|
||||
"Adresaci": [
|
||||
{
|
||||
"Id": send_data['data']['Id'],
|
||||
"IdReceiver": "",
|
||||
"Name": send_data['data']['Name'],
|
||||
"Role": send_data['data']['Role'],
|
||||
"UnitId": send_data['data']['UnitId'],
|
||||
"IdLogin": send_data['data']['IdLogin'],
|
||||
"PushWiadomosc": False,
|
||||
"Hash": send_data['data']['Hash'],
|
||||
"Date": None,
|
||||
"IsMarked": False
|
||||
}
|
||||
],
|
||||
"WyslijJako": student_data,
|
||||
"WiadomoscAdresatLogin": "",
|
||||
"IdWiadomoscAdresatLogin": None,
|
||||
"RolaNadawcy": 0,
|
||||
"NieprzeczytanePrzeczytane": "0/0",
|
||||
"NadawcaNazwa": "Brak nadawcy",
|
||||
"IdNadawca": 0,
|
||||
"AdresaciNazwa": "Brak adresata"
|
||||
}
|
||||
}
|
||||
|
||||
send = sess.post(f'{link}/NowaWiadomosc.mvc/InsertWiadomosc', data=json.dumps(payload))
|
||||
|
||||
return send.json()
|
||||
|
||||
def get_message_content(register_id, students, oun, s, date, school_year, symbol, message_id):
|
||||
with open('app/API/headers.json') as f:
|
||||
headers = json.load(f)
|
||||
|
||||
if oun == 'http://uonetplus-uczen.fakelog.tk/powiatwulkanowy/123458':
|
||||
link = f'http://uonetplus-uzytkownik.fakelog.tk/{symbol}'
|
||||
else:
|
||||
link = f'https://uonetplus-uzytkownik.vulcan.net.pl/{symbol}'
|
||||
|
||||
sess = requests.Session()
|
||||
|
||||
sess.cookies.update(s)
|
||||
sess.headers.update(headers)
|
||||
|
||||
index = sess.get(link)
|
||||
|
||||
antiForgeryToken = re.search("antiForgeryToken: '(.)*'", index.text)
|
||||
antiForgeryToken = antiForgeryToken.group()
|
||||
antiForgeryToken = antiForgeryToken.replace('antiForgeryToken: ', '').replace("'", "")
|
||||
|
||||
appGuid = re.search("appGuid: '(.)*'", index.text)
|
||||
appGuid = appGuid.group()
|
||||
appGuid = appGuid.replace('appGuid: ', '').replace("'", "")
|
||||
|
||||
sess.headers.update({
|
||||
'X-V-RequestVerificationToken': antiForgeryToken,
|
||||
'X-V-AppGuid': appGuid
|
||||
})
|
||||
|
||||
payload = {
|
||||
'messageId': message_id
|
||||
}
|
||||
|
||||
content = sess.post(f'{link}/Wiadomosc.mvc/GetInboxMessageDetails', data=json.dumps(payload))
|
||||
|
||||
if content.status_code != 200:
|
||||
while True:
|
||||
content = sess.post(f'{link}/Wiadomosc.mvc/GetInboxMessageDetails', data=json.dumps(payload))
|
||||
if content.status_code == 200:
|
||||
break
|
||||
|
||||
return content.json()
|
23
app/API/mobile_access.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
import json
|
||||
import requests
|
||||
from .generate_cookies import autogenerate_cookies
|
||||
|
||||
def get_registered_devices(register_id, students, oun, s):
|
||||
cookies = autogenerate_cookies(students, s)
|
||||
|
||||
with open('app/API/headers.json') as f:
|
||||
headers = json.load(f)
|
||||
|
||||
registered = requests.post(oun+'/ZarejestrowaneUrzadzenia.mvc/Get', headers=headers, cookies=cookies)
|
||||
|
||||
return registered.json()
|
||||
|
||||
def register_device(register_id, students, oun, s):
|
||||
cookies = autogenerate_cookies(students, s)
|
||||
|
||||
with open('app/API/headers.json') as f:
|
||||
headers = json.load(f)
|
||||
|
||||
register_data = requests.post(oun+'/RejestracjaUrzadzeniaToken.mvc/Get', headers=headers, cookies=cookies)
|
||||
|
||||
return register_data.json()
|
13
app/API/notes.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
import json
|
||||
import requests
|
||||
from .generate_cookies import autogenerate_cookies
|
||||
|
||||
def get_notes(register_id, students, oun, s):
|
||||
cookies = autogenerate_cookies(students, s)
|
||||
|
||||
with open('app/API/headers.json') as f:
|
||||
headers = json.load(f)
|
||||
|
||||
notes = requests.post(oun+'/UwagiIOsiagniecia.mvc/Get', headers=headers, cookies=cookies)
|
||||
|
||||
return notes.json()
|
13
app/API/school_data.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
import json
|
||||
import requests
|
||||
from .generate_cookies import autogenerate_cookies
|
||||
|
||||
def get_school_data(register_id, students, oun, s):
|
||||
cookies = autogenerate_cookies(students, s)
|
||||
|
||||
with open('app/API/headers.json') as f:
|
||||
headers = json.load(f)
|
||||
|
||||
school_data = requests.post(oun+'/SzkolaINauczyciele.mvc/Get', headers=headers, cookies=cookies)
|
||||
|
||||
return school_data.json()
|
24
app/API/stats.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
import json
|
||||
import requests
|
||||
from .generate_cookies import autogenerate_cookies
|
||||
|
||||
def get_partial(register_id, students, oun, s):
|
||||
cookies = autogenerate_cookies(students, s)
|
||||
|
||||
with open('app/API/headers.json') as f:
|
||||
headers = json.load(f)
|
||||
|
||||
partial = requests.post(oun+'/Statystyki.mvc/GetOcenyCzastkowe', headers=headers, cookies=cookies, json={'idOkres': register_id})
|
||||
|
||||
return partial.json()
|
||||
|
||||
def get_year(register_id, students, oun, s):
|
||||
|
||||
cookies = autogenerate_cookies(students, s)
|
||||
|
||||
with open('app/API/headers.json') as f:
|
||||
headers = json.load(f)
|
||||
|
||||
year = requests.post(oun+'/Statystyki.mvc/GetOcenyRoczne', headers=headers, cookies=cookies, json={'idOkres': register_id})
|
||||
|
||||
return year.json()
|
13
app/API/student_data.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
import json
|
||||
import requests
|
||||
from .generate_cookies import autogenerate_cookies
|
||||
|
||||
def get_student_data(register_id, students, oun, s):
|
||||
cookies = autogenerate_cookies(students, s)
|
||||
|
||||
with open('app/API/headers.json') as f:
|
||||
headers = json.load(f)
|
||||
|
||||
student_data = requests.post(f'{oun}/Uczen.mvc/Get', headers=headers, cookies=cookies)
|
||||
|
||||
return student_data.json()
|
14
app/API/timetable.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
import json
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
from .generate_cookies import autogenerate_cookies
|
||||
|
||||
def get_timetable(register_id, students, oun, s, date):
|
||||
cookies = autogenerate_cookies(students, s)
|
||||
|
||||
with open('app/API/headers.json') as f:
|
||||
headers = json.load(f)
|
||||
|
||||
timetable = requests.post(oun+'/PlanZajec.mvc/Get', headers=headers, cookies=cookies, json={'data': date})
|
||||
|
||||
return timetable.json()
|
3
app/admin.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
5
app/apps.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class WulkanowyConfig(AppConfig):
|
||||
name = 'Wulkanowy'
|
9
app/decrypt.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
import json
|
||||
from cryptography.fernet import Fernet
|
||||
|
||||
def decrypt_cookies(s, key):
|
||||
s = bytes(s, 'utf-8')
|
||||
key = Fernet(key)
|
||||
s = key.decrypt(s)
|
||||
s = json.loads(s.decode('utf-8'))
|
||||
return s
|
2
app/forms.py
Normal file
|
@ -0,0 +1,2 @@
|
|||
from django import forms
|
||||
|
86
app/login.py
Normal file
|
@ -0,0 +1,86 @@
|
|||
import os
|
||||
import sys
|
||||
import requests
|
||||
from django.contrib.sessions.models import Session
|
||||
from django.http import JsonResponse
|
||||
from django import template
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.shortcuts import render
|
||||
import json
|
||||
import requests
|
||||
from django.shortcuts import redirect
|
||||
from bs4 import BeautifulSoup
|
||||
import datetime
|
||||
|
||||
def sender(url, loginName, Password, params_names, fail_phrase, symbol, diary_url, s):
|
||||
data = [params_names[0], loginName, params_names[1], Password]
|
||||
|
||||
sender_return = send(url, data, fail_phrase, diary_url, symbol, s)
|
||||
if sender_return == {'success': False}:
|
||||
return {'success': False}
|
||||
else:
|
||||
return sender_return
|
||||
|
||||
def send(url, data, fail, diary_url, symbol, s):
|
||||
ready_data = {data[0]: data[1], data[2]: data[3]}
|
||||
page = s.post(url=url, data=ready_data)
|
||||
if fail in page.text:
|
||||
return {'success': False}
|
||||
else:
|
||||
if diary_url == 'http://cufs.fakelog.tk/':
|
||||
page = s.get('http://cufs.fakelog.tk/powiatwulkanowy/FS/LS?wa=wsignin1.0&wtrealm=http://uonetplus.fakelog.localhost:300/powiatwulkanowy/LoginEndpoint.aspx&wctx=http://uonetplus.fakelog.localhost:300/powiatwulkanowy/LoginEndpoint.aspx')
|
||||
bs = BeautifulSoup(page.text, 'html.parser')
|
||||
wa = bs.find('input', {'name': 'wa'})['value']
|
||||
cert = bs.find('input', {'name': 'wresult'})['value']
|
||||
wctx = bs.find('input', {'name': 'wctx'})['value']
|
||||
|
||||
crtr = s.post(url=wctx, headers={"User-Agent": "Wulkanowy-web :)"}, data={"wa": wa, "wresult": cert, "wctx": wctx})
|
||||
|
||||
if 'nie został zarejestrowany w bazie szkoły, do której się logujesz' in crtr.text:
|
||||
return {'success': False}
|
||||
|
||||
bs = BeautifulSoup(crtr.content, 'html.parser')
|
||||
for a in bs.find_all('a', title='Uczeń'):
|
||||
school_url = a['href']
|
||||
break
|
||||
|
||||
if diary_url == 'http://cufs.fakelog.tk/':
|
||||
school_url = 'http://uonetplus-uczen.fakelog.tk/powiatwulkanowy/123458'
|
||||
|
||||
cookies = get_cookies(symbol, school_url, s, diary_url)
|
||||
|
||||
return cookies
|
||||
|
||||
def get_cookies(symbol, school_url, s, diary_url):
|
||||
students = s.post(school_url+'/UczenDziennik.mvc/Get')
|
||||
register_id = students.json()['data'][0]['Okresy'][0]['Id']
|
||||
|
||||
now = datetime.datetime.now()
|
||||
weekday = now.weekday()
|
||||
|
||||
for x in range(7):
|
||||
if weekday == x:
|
||||
now = now - datetime.timedelta(days=x)
|
||||
|
||||
day = now.day
|
||||
month = now.month
|
||||
year = now.year
|
||||
|
||||
date = datetime.date(year, month, day).isoformat()
|
||||
|
||||
date = f'{date}T00:00:00'
|
||||
|
||||
school_year = students.json()['data'][0]['DziennikRokSzkolny']
|
||||
|
||||
data = {
|
||||
'register_id': register_id,
|
||||
'students': students.json(),
|
||||
'school_url': school_url,
|
||||
'date': str(date),
|
||||
'school_year': school_year,
|
||||
'symbol': symbol,
|
||||
's': s.cookies.get_dict(),
|
||||
'diary_url': diary_url
|
||||
}
|
||||
|
||||
return data
|
1
app/models.py
Normal file
|
@ -0,0 +1 @@
|
|||
from django.db import models
|
3
app/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
445
app/views.py
Normal file
|
@ -0,0 +1,445 @@
|
|||
from requests import get
|
||||
from cryptography.fernet import Fernet
|
||||
from django.contrib.sessions.backends.db import SessionStore
|
||||
from django.http import HttpResponse, JsonResponse
|
||||
from django.shortcuts import render
|
||||
import json
|
||||
import requests
|
||||
from rest_framework.decorators import api_view
|
||||
from django.core import serializers
|
||||
from django.shortcuts import redirect
|
||||
from django.contrib.sessions.models import Session
|
||||
from .login import sender
|
||||
from .API.grades import get_grades
|
||||
from .API.exams import get_exams
|
||||
from .API.timetable import get_timetable
|
||||
from .API.notes import get_notes
|
||||
from .API.attendance import get_attendance
|
||||
from .API.messages import get_received_messages, get_sent_messages, get_deleted_messages, get_recipients, send_message, get_message_content
|
||||
from .API.homeworks import get_homeworks
|
||||
from .API.mobile_access import get_registered_devices, register_device
|
||||
from .API.school_data import get_school_data
|
||||
from .API.dashboard import get_dashboard
|
||||
from .API.student_data import get_student_data
|
||||
from .API.stats import get_partial, get_year
|
||||
from .decrypt import decrypt_cookies
|
||||
import datetime
|
||||
|
||||
#API
|
||||
@api_view(['POST'])
|
||||
def login(request, *args, **kwargs):
|
||||
data = json.loads(request.body)
|
||||
loginName = data['loginName']
|
||||
Password = data['Password']
|
||||
symbol = data['Symbol']
|
||||
diary_url = data['diaryUrl']
|
||||
if diary_url != 'http://cufs.fakelog.tk/':
|
||||
link = f'{diary_url}{symbol}/Account/LogOn?ReturnUrl=%2F{symbol}%2FFS%2FLS%3Fwa%3Dwsignin1.0%26wtrealm%3Dhttps%253a%252f%252fuonetplus.vulcan.net.pl%252f{symbol}%252fLoginEndpoint.aspx%26wctx%3Dhttps%253a%252f%252fuonetplus.vulcan.net.pl%252f{symbol}%252fLoginEndpoint.aspx'
|
||||
else:
|
||||
link = 'http://cufs.fakelog.tk/powiatwulkanowy/FS/LS?wa=wsignin1.0&wtrealm=http://uonetplus.fakelog.localhost:300/powiatwulkanowy/LoginEndpoint.aspx&wctx=http://uonetplus.fakelog.localhost:300/powiatwulkanowy/LoginEndpoint.aspx'
|
||||
s = requests.Session()
|
||||
sender_return = sender(link, loginName, Password, ('loginName', 'Password'), 'Zła nazwa użytkownika lub hasło', symbol, diary_url, s)
|
||||
if sender_return == {'success': False}:
|
||||
data_response = {
|
||||
'success': False
|
||||
}
|
||||
else:
|
||||
request.session['is_logged'] = True
|
||||
request.session[request.session.session_key] = Fernet.generate_key().decode('utf-8')
|
||||
rkey = Fernet(bytes(request.session[request.session.session_key], 'utf-8'))
|
||||
|
||||
sender_return['s'] = json.dumps(sender_return['s'])
|
||||
sender_return['s'] = sender_return['s'].encode()
|
||||
sender_return['s'] = rkey.encrypt(sender_return['s'])
|
||||
sender_return['s'] = sender_return['s'].decode('utf-8')
|
||||
data_response = {'success': True, 'data': sender_return}
|
||||
return JsonResponse(data_response)
|
||||
|
||||
@api_view(['POST'])
|
||||
def grades(request, *args, **kwargs):
|
||||
if request.session.has_key('is_logged'):
|
||||
data = json.loads(request.body)
|
||||
register_id = data['data']['register_id']
|
||||
students = data['data']['students']
|
||||
school_url = data['data']['school_url']
|
||||
s = data['data']['s']
|
||||
key = bytes(request.session[request.session.session_key], 'utf-8')
|
||||
s = decrypt_cookies(s, key)
|
||||
grades = get_grades(register_id, students, school_url, s)
|
||||
return JsonResponse(grades)
|
||||
else:
|
||||
return redirect('../')
|
||||
|
||||
@api_view(['POST'])
|
||||
def timetable(request, *args, **kwargs):
|
||||
if request.session.has_key('is_logged'):
|
||||
data = json.loads(request.body)
|
||||
week = data['week']
|
||||
data = json.loads(data['cookies'])
|
||||
register_id = data['data']['register_id']
|
||||
students = data['data']['students']
|
||||
school_url = data['data']['school_url']
|
||||
s = data['data']['s']
|
||||
key = bytes(request.session[request.session.session_key], 'utf-8')
|
||||
s = decrypt_cookies(s, key)
|
||||
now = datetime.datetime.now()
|
||||
weekday = now.weekday()
|
||||
|
||||
for x in range(7):
|
||||
if weekday == x:
|
||||
now = now - datetime.timedelta(days=x)
|
||||
|
||||
now = now + datetime.timedelta(days=week*7)
|
||||
|
||||
day = now.day
|
||||
month = now.month
|
||||
year = now.year
|
||||
|
||||
date = datetime.date(year, month, day).isoformat()
|
||||
|
||||
date = f'{date}T00:00:00'
|
||||
timetable = get_timetable(register_id, students, school_url, s, date)
|
||||
return JsonResponse(timetable)
|
||||
else:
|
||||
return redirect('../')
|
||||
|
||||
@api_view(['POST'])
|
||||
def exams(request, *args, **kwargs):
|
||||
if request.session.has_key('is_logged'):
|
||||
data = json.loads(request.body)
|
||||
week = data['week']
|
||||
data = json.loads(data['cookies'])
|
||||
register_id = data['data']['register_id']
|
||||
students = data['data']['students']
|
||||
school_url = data['data']['school_url']
|
||||
s = data['data']['s']
|
||||
key = bytes(request.session[request.session.session_key], 'utf-8')
|
||||
s = decrypt_cookies(s, key)
|
||||
now = datetime.datetime.now()
|
||||
weekday = now.weekday()
|
||||
|
||||
for x in range(7):
|
||||
if weekday == x:
|
||||
now = now - datetime.timedelta(days=x)
|
||||
|
||||
now = now + datetime.timedelta(days=week*7)
|
||||
|
||||
day = now.day
|
||||
month = now.month
|
||||
year = now.year
|
||||
|
||||
date = datetime.date(year, month, day).isoformat()
|
||||
|
||||
date = f'{date}T00:00:00'
|
||||
school_year = data['data']['school_year']
|
||||
exams = get_exams(register_id, students, school_url, s, date, school_year)
|
||||
return JsonResponse(exams)
|
||||
else:
|
||||
return redirect('../')
|
||||
|
||||
@api_view(['POST'])
|
||||
def homeworks(request, *args, **kwargs):
|
||||
if request.session.has_key('is_logged'):
|
||||
data = json.loads(request.body)
|
||||
week = data['week']
|
||||
data = json.loads(data['cookies'])
|
||||
register_id = data['data']['register_id']
|
||||
students = data['data']['students']
|
||||
school_url = data['data']['school_url']
|
||||
s = data['data']['s']
|
||||
key = bytes(request.session[request.session.session_key], 'utf-8')
|
||||
s = decrypt_cookies(s, key)
|
||||
now = datetime.datetime.now()
|
||||
weekday = now.weekday()
|
||||
|
||||
for x in range(7):
|
||||
if weekday == x:
|
||||
now = now - datetime.timedelta(days=x)
|
||||
|
||||
now = now + datetime.timedelta(days=week*7)
|
||||
|
||||
day = now.day
|
||||
month = now.month
|
||||
year = now.year
|
||||
|
||||
date = datetime.date(year, month, day).isoformat()
|
||||
|
||||
date = f'{date}T00:00:00'
|
||||
school_year = data['data']['school_year']
|
||||
homeworks = get_homeworks(register_id, students, school_url, s, date, school_year)
|
||||
return JsonResponse(homeworks)
|
||||
else:
|
||||
return redirect('../')
|
||||
|
||||
@api_view(['POST'])
|
||||
def attendance(request, *args, **kwargs):
|
||||
if request.session.has_key('is_logged'):
|
||||
data = json.loads(request.body)
|
||||
week = data['week']
|
||||
data = json.loads(data['cookies'])
|
||||
register_id = data['data']['register_id']
|
||||
students = data['data']['students']
|
||||
school_url = data['data']['school_url']
|
||||
s = data['data']['s']
|
||||
key = bytes(request.session[request.session.session_key], 'utf-8')
|
||||
s = decrypt_cookies(s, key)
|
||||
now = datetime.datetime.now()
|
||||
weekday = now.weekday()
|
||||
|
||||
for x in range(7):
|
||||
if weekday == x:
|
||||
now = now - datetime.timedelta(days=x)
|
||||
|
||||
now = now + datetime.timedelta(days=week*7)
|
||||
|
||||
day = now.day
|
||||
month = now.month
|
||||
year = now.year
|
||||
|
||||
date = datetime.date(year, month, day).isoformat()
|
||||
|
||||
date = f'{date}T00:00:00'
|
||||
attendance = get_attendance(register_id, students, school_url, s, date)
|
||||
return JsonResponse(attendance, safe=False)
|
||||
else:
|
||||
return redirect('../')
|
||||
|
||||
@api_view(['POST'])
|
||||
def notes(request, *args, **kwargs):
|
||||
if request.session.has_key('is_logged'):
|
||||
data = json.loads(request.body)
|
||||
register_id = data['data']['register_id']
|
||||
students = data['data']['students']
|
||||
school_url = data['data']['school_url']
|
||||
s = data['data']['s']
|
||||
key = bytes(request.session[request.session.session_key], 'utf-8')
|
||||
s = decrypt_cookies(s, key)
|
||||
notes = get_notes(register_id, students, school_url, s)
|
||||
return JsonResponse(notes)
|
||||
else:
|
||||
return redirect('../')
|
||||
|
||||
@api_view(['POST'])
|
||||
def registered_devices(request, *args, **kwargs):
|
||||
if request.session.has_key('is_logged'):
|
||||
data = json.loads(request.body)
|
||||
register_id = data['data']['register_id']
|
||||
students = data['data']['students']
|
||||
school_url = data['data']['school_url']
|
||||
s = data['data']['s']
|
||||
key = bytes(request.session[request.session.session_key], 'utf-8')
|
||||
s = decrypt_cookies(s, key)
|
||||
registered = get_registered_devices(register_id, students, school_url, s)
|
||||
return JsonResponse(registered)
|
||||
else:
|
||||
return redirect('../')
|
||||
|
||||
@api_view(['POST'])
|
||||
def register_device_(request, *args, **kwargs):
|
||||
if request.session.has_key('is_logged'):
|
||||
data = json.loads(request.body)
|
||||
register_id = data['data']['register_id']
|
||||
students = data['data']['students']
|
||||
school_url = data['data']['school_url']
|
||||
s = data['data']['s']
|
||||
key = bytes(request.session[request.session.session_key], 'utf-8')
|
||||
s = decrypt_cookies(s, key)
|
||||
register_data = register_device(register_id, students, school_url, s)
|
||||
return JsonResponse(register_data)
|
||||
else:
|
||||
return redirect('../')
|
||||
|
||||
@api_view(['POST'])
|
||||
def received_messages(request, *args, **kwargs):
|
||||
if request.session.has_key('is_logged'):
|
||||
data = json.loads(request.body)
|
||||
register_id = data['data']['register_id']
|
||||
students = data['data']['students']
|
||||
school_url = data['data']['school_url']
|
||||
s = data['data']['s']
|
||||
key = bytes(request.session[request.session.session_key], 'utf-8')
|
||||
s = decrypt_cookies(s, key)
|
||||
date = data['data']['date']
|
||||
school_year = data['data']['school_year']
|
||||
symbol = data['data']['symbol']
|
||||
received_messages = get_received_messages(register_id, students, school_url, s, date, school_year, symbol)
|
||||
return JsonResponse(received_messages)
|
||||
else:
|
||||
return redirect('../')
|
||||
|
||||
@api_view(['POST'])
|
||||
def sent_messages(request, *args, **kwargs):
|
||||
if request.session.has_key('is_logged'):
|
||||
data = json.loads(request.body)
|
||||
register_id = data['data']['register_id']
|
||||
students = data['data']['students']
|
||||
school_url = data['data']['school_url']
|
||||
s = data['data']['s']
|
||||
key = bytes(request.session[request.session.session_key], 'utf-8')
|
||||
s = decrypt_cookies(s, key)
|
||||
date = data['data']['date']
|
||||
school_year = data['data']['school_year']
|
||||
symbol = data['data']['symbol']
|
||||
sent_messages = get_sent_messages(register_id, students, school_url, s, date, school_year, symbol)
|
||||
return JsonResponse(sent_messages)
|
||||
else:
|
||||
return redirect('../')
|
||||
|
||||
@api_view(['POST'])
|
||||
def deleted_messages(request, *args, **kwargs):
|
||||
if request.session.has_key('is_logged'):
|
||||
data = json.loads(request.body)
|
||||
register_id = data['data']['register_id']
|
||||
students = data['data']['students']
|
||||
school_url = data['data']['school_url']
|
||||
s = data['data']['s']
|
||||
key = bytes(request.session[request.session.session_key], 'utf-8')
|
||||
s = decrypt_cookies(s, key)
|
||||
date = data['data']['date']
|
||||
school_year = data['data']['school_year']
|
||||
symbol = data['data']['symbol']
|
||||
deleted_messages = get_deleted_messages(register_id, students, school_url, s, date, school_year, symbol)
|
||||
return JsonResponse(deleted_messages)
|
||||
else:
|
||||
return redirect('../')
|
||||
|
||||
@api_view(['POST'])
|
||||
def recipients(request, *args, **kwargs):
|
||||
if request.session.has_key('is_logged'):
|
||||
data = json.loads(request.body)
|
||||
register_id = data['data']['register_id']
|
||||
students = data['data']['students']
|
||||
school_url = data['data']['school_url']
|
||||
s = data['data']['s']
|
||||
key = bytes(request.session[request.session.session_key], 'utf-8')
|
||||
s = decrypt_cookies(s, key)
|
||||
date = data['data']['date']
|
||||
school_year = data['data']['school_year']
|
||||
symbol = data['data']['symbol']
|
||||
recipients = get_recipients(register_id, students, school_url, s, date, school_year, symbol)
|
||||
return JsonResponse(recipients)
|
||||
else:
|
||||
return redirect('../')
|
||||
|
||||
@api_view(['POST'])
|
||||
def school_data(request, *args, **kwargs):
|
||||
if request.session.has_key('is_logged'):
|
||||
data = json.loads(request.body)
|
||||
register_id = data['data']['register_id']
|
||||
students = data['data']['students']
|
||||
school_url = data['data']['school_url']
|
||||
s = data['data']['s']
|
||||
key = bytes(request.session[request.session.session_key], 'utf-8')
|
||||
s = decrypt_cookies(s, key)
|
||||
school_data = get_school_data(register_id, students, school_url, s)
|
||||
return JsonResponse(school_data)
|
||||
else:
|
||||
return redirect('../')
|
||||
|
||||
@api_view(['POST'])
|
||||
def dashboard(request, *args, **kwargs):
|
||||
if request.session.has_key('is_logged'):
|
||||
data = json.loads(request.body)
|
||||
register_id = data['data']['register_id']
|
||||
students = data['data']['students']
|
||||
s = data['data']['s']
|
||||
key = bytes(request.session[request.session.session_key], 'utf-8')
|
||||
s = decrypt_cookies(s, key)
|
||||
diary_url = data['data']['diary_url']
|
||||
symbol = data['data']['symbol']
|
||||
dashboard = get_dashboard(register_id, students, s, diary_url, symbol)
|
||||
return JsonResponse(dashboard)
|
||||
else:
|
||||
return redirect('../')
|
||||
|
||||
@api_view(['POST'])
|
||||
def send(request, *args, **kwargs):
|
||||
if request.session.has_key('is_logged'):
|
||||
data = json.loads(request.body)
|
||||
cookies_data = json.loads(data['cookies_data'])
|
||||
register_id = cookies_data['data']['register_id']
|
||||
students = cookies_data['data']['students']
|
||||
school_url = cookies_data['data']['school_url']
|
||||
s = cookies_data['data']['s']
|
||||
key = bytes(request.session[request.session.session_key], 'utf-8')
|
||||
s = decrypt_cookies(s, key)
|
||||
date = cookies_data['data']['date']
|
||||
school_year = cookies_data['data']['school_year']
|
||||
symbol = cookies_data['data']['symbol']
|
||||
send_data = {'data': data['data'], 'subject': data['subject'], 'content': data['content']}
|
||||
send = send_message(register_id, students, school_url, s, date, school_year, symbol, send_data)
|
||||
return JsonResponse(send, safe=False)
|
||||
else:
|
||||
return redirect('../')
|
||||
|
||||
@api_view(['POST'])
|
||||
def message_content(request, *args, **kwargs):
|
||||
if request.session.has_key('is_logged'):
|
||||
data = json.loads(request.body)
|
||||
cookies_data = json.loads(data['cookies_data'])
|
||||
register_id = cookies_data['data']['register_id']
|
||||
students = cookies_data['data']['students']
|
||||
school_url = cookies_data['data']['school_url']
|
||||
s = cookies_data['data']['s']
|
||||
key = bytes(request.session[request.session.session_key], 'utf-8')
|
||||
s = decrypt_cookies(s, key)
|
||||
date = cookies_data['data']['date']
|
||||
school_year = cookies_data['data']['school_year']
|
||||
symbol = cookies_data['data']['symbol']
|
||||
message_id = data['message_id']
|
||||
content = get_message_content(register_id, students, school_url, s, date, school_year, symbol, message_id)
|
||||
return JsonResponse(content, safe=False)
|
||||
else:
|
||||
return redirect('../')
|
||||
|
||||
@api_view(['POST'])
|
||||
def student_data(request, *args, **kwargs):
|
||||
if request.session.has_key('is_logged'):
|
||||
data = json.loads(request.body)
|
||||
register_id = data['data']['register_id']
|
||||
students = data['data']['students']
|
||||
school_url = data['data']['school_url']
|
||||
s = data['data']['s']
|
||||
key = bytes(request.session[request.session.session_key], 'utf-8')
|
||||
s = decrypt_cookies(s, key)
|
||||
data = get_student_data(register_id, students, school_url, s)
|
||||
return JsonResponse(data)
|
||||
else:
|
||||
return redirect('../')
|
||||
|
||||
#STATS
|
||||
@api_view(['POST'])
|
||||
def partial(request, *args, **kwargs):
|
||||
if request.session.has_key('is_logged'):
|
||||
data = json.loads(request.body)
|
||||
register_id = data['data']['register_id']
|
||||
students = data['data']['students']
|
||||
school_url = data['data']['school_url']
|
||||
s = data['data']['s']
|
||||
key = bytes(request.session[request.session.session_key], 'utf-8')
|
||||
s = decrypt_cookies(s, key)
|
||||
partial_stats = get_partial(register_id, students, school_url, s)
|
||||
return JsonResponse(partial_stats)
|
||||
else:
|
||||
return redirect('../')
|
||||
|
||||
@api_view(['POST'])
|
||||
def year(request, *args, **kwargs):
|
||||
if request.session.has_key('is_logged'):
|
||||
data = json.loads(request.body)
|
||||
register_id = data['data']['register_id']
|
||||
students = data['data']['students']
|
||||
school_url = data['data']['school_url']
|
||||
s = data['data']['s']
|
||||
key = bytes(request.session[request.session.session_key], 'utf-8')
|
||||
s = decrypt_cookies(s, key)
|
||||
year_stats = get_year(register_id, students, school_url, s)
|
||||
return JsonResponse(year_stats)
|
||||
else:
|
||||
return redirect('../')
|
||||
|
||||
@api_view(['GET'])
|
||||
def log_out(request, *args, **kwargs):
|
||||
del request.session[request.session.session_key]
|
||||
del request.session['is_logged']
|
||||
return JsonResponse({'logOut': True})
|
|
@ -1,15 +0,0 @@
|
|||
# Wulkanowy Web Backend
|
||||
|
||||
Based on [Marioneq's UonetplusAPI](https://github.com/Marioneq4958/uonetplus_api)
|
||||
|
||||
## 1. Install dependencies
|
||||
|
||||
```sh
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## 2. Start the server
|
||||
|
||||
```sh
|
||||
py -m main
|
||||
```
|
|
@ -1,193 +0,0 @@
|
|||
from fastapi import APIRouter, HTTPException, Response
|
||||
from starlette import status
|
||||
from bs4 import BeautifulSoup
|
||||
from urllib.parse import quote
|
||||
from datetime import datetime
|
||||
from cryptography.fernet import Fernet
|
||||
import requests
|
||||
import re
|
||||
from app import models, paths
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post("/login")
|
||||
def login(data: models.Login, response: Response):
|
||||
session = requests.Session()
|
||||
cers = send_credentials(data.username, data.password, data.symbol, data.host, data.ssl, session)
|
||||
students = get_students(data.symbol, data.host, data.ssl, cers, session)
|
||||
cookies = get_cookies(data.ssl, data.host, data.symbol, session, students, response)
|
||||
|
||||
return cookies
|
||||
|
||||
|
||||
def send_credentials(username: str, password: str, symbol: str, host: str, ssl: bool, session):
|
||||
realm = build_url(subd="uonetplus", host=host, ssl=ssl)
|
||||
url = build_url(
|
||||
subd="cufs",
|
||||
host=host,
|
||||
path=paths.CUFS.START,
|
||||
realm=quote(quote(realm, safe=""), safe=""),
|
||||
symbol=symbol,
|
||||
ssl=ssl,
|
||||
)
|
||||
payload = {"LoginName": username, "Password": password}
|
||||
try:
|
||||
page = session.post(url, payload)
|
||||
if page.status_code == 404:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST, detail="Host or ssl is invalid"
|
||||
)
|
||||
except:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST, detail="Host or ssl is invalid"
|
||||
)
|
||||
soup = BeautifulSoup(page.text, "lxml")
|
||||
error_tags = soup.select(".ErrorMessage, #ErrorTextLabel, #loginArea #errorText")
|
||||
for error_tag in error_tags:
|
||||
msg = re.sub(r"\s+", " ", error_tag.text).strip()
|
||||
if msg:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN, detail="Username or password is incorrect"
|
||||
)
|
||||
wa: str = soup.select_one('input[name="wa"]')["value"]
|
||||
wresult: str = soup.select_one('input[name="wresult"]')["value"]
|
||||
wctx_tag = soup.select_one('input[name="wctx"]')
|
||||
wctx: str = wctx_tag["value"] if wctx_tag else None
|
||||
cers = {"wa": wa, "wresult": wresult, "wctx": wctx}
|
||||
|
||||
return cers
|
||||
|
||||
|
||||
def build_url(subd: str = None, host: str = None, path: str = None, ssl: bool = True, **kwargs):
|
||||
if ssl:
|
||||
url = "https://"
|
||||
else:
|
||||
url = "http://"
|
||||
if subd:
|
||||
url += subd + "."
|
||||
url += str(host)
|
||||
if path:
|
||||
url += path
|
||||
if not kwargs.get("symbol"):
|
||||
kwargs["symbol"] = "Deflaut"
|
||||
|
||||
for k in kwargs:
|
||||
url = url.replace(f"{{{k.upper()}}}", str(kwargs[k]))
|
||||
|
||||
return url
|
||||
|
||||
|
||||
def get_cookies(ssl: bool, host: str, symbol: str, session, students, response):
|
||||
key = Fernet.generate_key().decode("utf-8")
|
||||
fernet = Fernet(bytes(key, "utf-8"))
|
||||
vulcan_cookies = session.cookies.get_dict()
|
||||
cookies = fernet.encrypt(str(vulcan_cookies).encode("utf-8"))
|
||||
response.set_cookie(key="key", value=key, max_age=1200)
|
||||
data = {
|
||||
"students": students,
|
||||
"vulcan_cookies": cookies,
|
||||
"symbol": symbol,
|
||||
"host": host,
|
||||
"ssl": ssl,
|
||||
}
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def get_students(symbol: str, host: str, ssl: bool, cers, session):
|
||||
students = []
|
||||
url = build_url(subd="uonetplus", path=paths.UONETPLUS.START, symbol=symbol, host=host, ssl=ssl)
|
||||
crtr = session.post(
|
||||
url=url,
|
||||
headers={
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0"
|
||||
},
|
||||
data=cers,
|
||||
)
|
||||
if not "nie został zarejestrowany" in crtr.text:
|
||||
soup = BeautifulSoup(crtr.text, "lxml")
|
||||
schools = soup.select('.panel.linkownia.pracownik.klient a[href*="uonetplus-uczen"]')
|
||||
for school in schools:
|
||||
school_id = school["href"].split("/")[4]
|
||||
url = build_url(
|
||||
subd="uonetplus-uczen",
|
||||
path=paths.UCZEN.START,
|
||||
symbol=symbol,
|
||||
host=host,
|
||||
schoolid=school_id,
|
||||
ssl=ssl,
|
||||
)
|
||||
page = session.get(url)
|
||||
school_name = get_script_param(page.text, "organizationName")
|
||||
anti_forgery_token = get_script_param(page.text, "antiForgeryToken")
|
||||
app_guid = get_script_param(page.text, "appGuid")
|
||||
version = get_script_param(page.text, "version")
|
||||
url = build_url(
|
||||
subd="uonetplus-uczen",
|
||||
path=paths.UCZEN.UCZENDZIENNIK_GET,
|
||||
symbol=symbol,
|
||||
host=host,
|
||||
schoolid=school_id,
|
||||
ssl=ssl,
|
||||
)
|
||||
students_response = session.post(url)
|
||||
for student in students_response.json()["data"]:
|
||||
semesters = []
|
||||
headers = {
|
||||
"Accept": "*/*",
|
||||
"Accept-Encoding": "gzip, deflate, br",
|
||||
"Connection": "keep-alive",
|
||||
"X-V-AppVersion": version,
|
||||
"X-V-AppGuid": app_guid,
|
||||
"X-V-RequestVerificationToken": anti_forgery_token,
|
||||
}
|
||||
for semester in student["Okresy"]:
|
||||
semester = models.Semester(
|
||||
number=semester["NumerOkresu"],
|
||||
level=semester["Poziom"],
|
||||
start=datetime.fromisoformat(semester["DataOd"]),
|
||||
end=datetime.fromisoformat(semester["DataDo"]),
|
||||
class_id=semester["IdOddzial"],
|
||||
unit_id=semester["IdJednostkaSprawozdawcza"],
|
||||
current=semester["IsLastOkres"],
|
||||
id=semester["Id"],
|
||||
)
|
||||
semesters.append(semester)
|
||||
student = models.Student(
|
||||
id=student["Id"],
|
||||
student_id=student["IdUczen"],
|
||||
student_name=student["UczenImie"],
|
||||
student_second_name=student["UczenImie2"],
|
||||
student_surname=student["UczenNazwisko"],
|
||||
is_register=student["IsDziennik"],
|
||||
register_id=student["IdDziennik"],
|
||||
kindergarten_register_id=student["IdPrzedszkoleDziennik"],
|
||||
level=student["Poziom"],
|
||||
symbol=student["Symbol"],
|
||||
name=student["Nazwa"],
|
||||
year=student["DziennikRokSzkolny"],
|
||||
start=datetime.fromisoformat(student["DziennikDataOd"]),
|
||||
end=datetime.fromisoformat(student["DziennikDataDo"]),
|
||||
full_name=student["UczenPelnaNazwa"],
|
||||
school_id=school_id,
|
||||
school_symbol=symbol,
|
||||
school_name=school_name,
|
||||
cookies={
|
||||
"idBiezacyDziennik": str(student["IdDziennik"]),
|
||||
"idBiezacyUczen": str(student["IdUczen"]),
|
||||
"idBiezacyDziennikPrzedszkole": str(student["IdPrzedszkoleDziennik"]),
|
||||
"biezacyRokSzkolny": str(student["DziennikRokSzkolny"]),
|
||||
},
|
||||
headers=headers,
|
||||
semesters=semesters,
|
||||
)
|
||||
students.append(student)
|
||||
else:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Symbol is incorrect")
|
||||
return students
|
||||
|
||||
|
||||
def get_script_param(text: str, param: str, default: str = None) -> str:
|
||||
m = re.search(f"{param}: '(.+?)'", text)
|
||||
return m.group(1) if m else default
|
|
@ -1,222 +0,0 @@
|
|||
from fastapi import APIRouter, HTTPException, Depends
|
||||
from fastapi.security import APIKeyCookie
|
||||
from starlette import status
|
||||
from app import models, paths
|
||||
import requests
|
||||
from datetime import datetime
|
||||
from cryptography.fernet import Fernet
|
||||
import ast
|
||||
|
||||
cookie_sec = APIKeyCookie(name="key")
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post("/uonetplus-uczen/notes")
|
||||
def get_notes(data: models.UonetPlusUczen, key: str = Depends(cookie_sec)):
|
||||
data.vulcan_cookies = encrypt_cookies(key, data.vulcan_cookies)
|
||||
path = paths.UCZEN.UWAGIIOSIAGNIECIA_GET
|
||||
response = get_response(data, path)
|
||||
notes = []
|
||||
for note in response.json()["data"]["Uwagi"]:
|
||||
note = models.Note(
|
||||
date=datetime.fromisoformat(note["DataWpisu"]).strftime("%d.%m.%Y %H:%M"),
|
||||
teacher=note["Nauczyciel"],
|
||||
category=note["Kategoria"],
|
||||
content=note["TrescUwagi"],
|
||||
points=note["Punkty"],
|
||||
show_points=int(note["PokazPunkty"]),
|
||||
category_type=bool(note["KategoriaTyp"]),
|
||||
)
|
||||
notes.append(note)
|
||||
notes_and_achievements = models.NotesAndAchievements(
|
||||
notes=notes, achievements=response.json()["data"]["Osiagniecia"]
|
||||
)
|
||||
return notes_and_achievements
|
||||
|
||||
|
||||
@router.post("/uonetplus-uczen/school-info")
|
||||
def get_school_info(data: models.UonetPlusUczen, key: str = Depends(cookie_sec)):
|
||||
data.vulcan_cookies = encrypt_cookies(key, data.vulcan_cookies)
|
||||
path = paths.UCZEN.SZKOLAINAUCZYCIELE_GET
|
||||
response = get_response(data, path)
|
||||
teachers = []
|
||||
school = models.School(
|
||||
name=response.json()["data"]["Szkola"]["Nazwa"],
|
||||
address=response.json()["data"]["Szkola"]["Adres"],
|
||||
contact=response.json()["data"]["Szkola"]["Kontakt"],
|
||||
headmaster=response.json()["data"]["Szkola"]["Dyrektor"],
|
||||
pedagogue=response.json()["data"]["Szkola"]["Pedagog"],
|
||||
)
|
||||
for teacher in response.json()["data"]["Nauczyciele"]:
|
||||
teacher = models.Teacher(name=teacher["Nauczyciel"], subject=teacher["Nazwa"])
|
||||
teachers.append(teacher)
|
||||
school_info = models.SchoolInfo(school=school, teachers=teachers)
|
||||
return school_info
|
||||
|
||||
|
||||
@router.post("/uonetplus-uczen/conferences")
|
||||
def get_conferences(data: models.UonetPlusUczen, key: str = Depends(cookie_sec)):
|
||||
data.vulcan_cookies = encrypt_cookies(key, data.vulcan_cookies)
|
||||
path = paths.UCZEN.ZEBRANIA_GET
|
||||
response = get_response(data, path)
|
||||
conferences = []
|
||||
for conference in response.json()["data"]:
|
||||
split = conference["Tytul"].split(", ")
|
||||
title = ", ".join(split[2:])
|
||||
date = datetime.strptime(split[1].replace(" godzina", ""), "%d.%m.%Y %H:%M")
|
||||
conference = models.Conference(
|
||||
title=title,
|
||||
subject=conference["TematZebrania"],
|
||||
agenda=conference["Agenda"],
|
||||
present_on_conference=conference["ObecniNaZebraniu"],
|
||||
online=conference["ZebranieOnline"],
|
||||
id=conference["Id"],
|
||||
date=date.strftime("%d.%m.%Y %H:%M"),
|
||||
)
|
||||
conferences.append(conference)
|
||||
return conferences
|
||||
|
||||
|
||||
@router.post("/uonetplus-uczen/grades")
|
||||
def get_grades(data: models.UonetPlusUczen, key: str = Depends(cookie_sec)):
|
||||
data.vulcan_cookies = encrypt_cookies(key, data.vulcan_cookies)
|
||||
path = paths.UCZEN.OCENY_GET
|
||||
response = get_response(data, path)
|
||||
subjects = []
|
||||
descriptive_grades = []
|
||||
for subject in response.json()["data"]["Oceny"]:
|
||||
subject_grades = []
|
||||
for grade in subject["OcenyCzastkowe"]:
|
||||
grade = models.Grade(
|
||||
entry=grade["Wpis"],
|
||||
color=grade["KolorOceny"],
|
||||
symbol=grade["KodKolumny"],
|
||||
description=grade["NazwaKolumny"],
|
||||
weight_value=grade["Waga"],
|
||||
date=grade["DataOceny"],
|
||||
teacher=grade["Nauczyciel"],
|
||||
)
|
||||
subject_grades.append(grade)
|
||||
subject = models.Subject(
|
||||
name=subject["Przedmiot"],
|
||||
visible_subject=subject["WidocznyPrzedmiot"],
|
||||
position=subject["Pozycja"],
|
||||
average=subject["Srednia"],
|
||||
proposed_grade=subject["ProponowanaOcenaRoczna"],
|
||||
final_grade=subject["OcenaRoczna"],
|
||||
proposed_points=subject["ProponowanaOcenaRocznaPunkty"],
|
||||
final_points=subject["OcenaRocznaPunkty"],
|
||||
grades=subject_grades,
|
||||
)
|
||||
subjects.append(subject)
|
||||
for descriptive_grade in response.json()["data"]["OcenyOpisowe"]:
|
||||
descriptive_grade = models.DescriptiveGrade(
|
||||
subject=descriptive_grade["NazwaPrzedmiotu"],
|
||||
description=descriptive_grade["Opis"],
|
||||
is_religion_or_ethics=descriptive_grade["IsReligiaEtyka"],
|
||||
)
|
||||
descriptive_grades.append(descriptive_grade)
|
||||
grades = models.Grades(
|
||||
is_average=response.json()["data"]["IsSrednia"],
|
||||
is_points=response.json()["data"]["IsPunkty"],
|
||||
subjects=subjects,
|
||||
descriptive_grades=descriptive_grades,
|
||||
)
|
||||
return grades
|
||||
|
||||
|
||||
@router.post("/uonetplus-uczen/mobile-access/get-registered-devices")
|
||||
def get_registered_devices(data: models.UonetPlusUczen, key: str = Depends(cookie_sec)):
|
||||
data.vulcan_cookies = encrypt_cookies(key, data.vulcan_cookies)
|
||||
path = paths.UCZEN.ZAREJESTROWANEURZADZENIA_GET
|
||||
response = get_response(data, path)
|
||||
registered_devices = []
|
||||
for device in response.json()["data"]:
|
||||
device = models.Device(
|
||||
id=device["Id"],
|
||||
name=device["NazwaUrzadzenia"],
|
||||
create_date=datetime.fromisoformat(device["DataUtworzenia"]).strftime("%d.%m.%Y %H:%M"),
|
||||
)
|
||||
registered_devices.append(device)
|
||||
return registered_devices
|
||||
|
||||
|
||||
@router.post("/uonetplus-uczen/mobile-access/register-device")
|
||||
def get_register_device_token(data: models.UonetPlusUczen, key: str = Depends(cookie_sec)):
|
||||
data.vulcan_cookies = encrypt_cookies(key, data.vulcan_cookies)
|
||||
path = paths.UCZEN.REJESTRACJAURZADZENIATOKEN_GET
|
||||
response = get_response(data, path)
|
||||
token_response = models.TokenResponse(
|
||||
token=response.json()["data"]["TokenKey"],
|
||||
symbol=response.json()["data"]["CustomerGroup"],
|
||||
pin=response.json()["data"]["PIN"],
|
||||
qr_code_image=response.json()["data"]["QrCodeImage"],
|
||||
)
|
||||
return token_response
|
||||
|
||||
|
||||
@router.post("/uonetplus-uczen/mobile-access/delete-registered-device")
|
||||
def get_register_device_token(data: models.UonetPlusUczen, key: str = Depends(cookie_sec)):
|
||||
data.vulcan_cookies = encrypt_cookies(key, data.vulcan_cookies)
|
||||
path = paths.UCZEN.ZAREJESTROWANEURZADZENIA_DELETE
|
||||
response = get_response(data, path)
|
||||
return response.json()
|
||||
|
||||
|
||||
def build_url(subd: str = None, host: str = None, path: str = None, ssl: bool = True, **kwargs):
|
||||
if ssl:
|
||||
url = "https://"
|
||||
else:
|
||||
url = "http://"
|
||||
if subd:
|
||||
url += subd + "."
|
||||
url += host
|
||||
if path:
|
||||
url += path
|
||||
if not kwargs.get("symbol"):
|
||||
kwargs["symbol"] = "Deflaut"
|
||||
|
||||
for k in kwargs:
|
||||
url = url.replace(f"{{{k.upper()}}}", str(kwargs[k]))
|
||||
|
||||
return url
|
||||
|
||||
|
||||
def get_response(data, path):
|
||||
session = requests.Session()
|
||||
data.vulcan_cookies.update(data.student)
|
||||
url = build_url(
|
||||
subd="uonetplus-uczen",
|
||||
path=path,
|
||||
symbol=data.symbol,
|
||||
host=data.host,
|
||||
schoolid=data.school_id,
|
||||
ssl=data.ssl,
|
||||
)
|
||||
response = session.post(
|
||||
url=url,
|
||||
headers=data.headers,
|
||||
json=data.payload,
|
||||
cookies=data.vulcan_cookies,
|
||||
)
|
||||
if response.status_code != 200:
|
||||
detail = "UONET+ error code: " + response.status_code
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=detail)
|
||||
if (
|
||||
"Wystąpił błąd aplikacji. Prosimy zalogować się ponownie. Jeśli problem będzie się powtarzał, prosimy o kontakt z serwisem."
|
||||
in response.text
|
||||
):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="UONET+ error"
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def encrypt_cookies(key: str, vulcan_cookies: str):
|
||||
fernet = Fernet(bytes(key, "utf-8"))
|
||||
cookies = fernet.decrypt((vulcan_cookies).encode())
|
||||
cookies = ast.literal_eval(cookies.decode("utf-8"))
|
||||
|
||||
return cookies
|
|
@ -1,7 +0,0 @@
|
|||
from .student import Student, Semester
|
||||
from .requests import Login, UonetPlusUczen
|
||||
from .notes import NotesAndAchievements, Note
|
||||
from .grades import Grades, Subject, Grade, DescriptiveGrade
|
||||
from .conferences import Conference
|
||||
from .school_info import SchoolInfo, School, Teacher
|
||||
from .mobile_access import Device, TokenResponse
|
|
@ -1,13 +0,0 @@
|
|||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class Conference(BaseModel):
|
||||
title: str
|
||||
subject: str
|
||||
agenda: str
|
||||
present_on_conference: str
|
||||
online: Optional[str]
|
||||
id: int
|
||||
date: str
|
|
@ -1,37 +0,0 @@
|
|||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class Grades(BaseModel):
|
||||
is_average: bool
|
||||
is_points: bool
|
||||
subjects: list
|
||||
descriptive_grades: list
|
||||
|
||||
|
||||
class Subject(BaseModel):
|
||||
name: str
|
||||
visible_subject: bool
|
||||
position: int
|
||||
average: float
|
||||
proposed_grade: Optional[str]
|
||||
fianl_grade: Optional[str]
|
||||
proposed_points: Optional[str]
|
||||
final_points: Optional[str]
|
||||
grades: list
|
||||
|
||||
|
||||
class Grade(BaseModel):
|
||||
entry: str
|
||||
color: str
|
||||
symbol: Optional[str]
|
||||
description: Optional[str]
|
||||
weight_value: float
|
||||
date: str
|
||||
teacher: str
|
||||
|
||||
|
||||
class DescriptiveGrade(BaseModel):
|
||||
subject: str
|
||||
description: str
|
||||
is_religion_or_ethics: bool
|
|
@ -1,15 +0,0 @@
|
|||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class Device(BaseModel):
|
||||
id: int
|
||||
name: Optional[str]
|
||||
create_date: Optional[str]
|
||||
|
||||
|
||||
class TokenResponse(BaseModel):
|
||||
token: str
|
||||
symbol: str
|
||||
pin: str
|
||||
qr_code_image: str
|
|
@ -1,17 +0,0 @@
|
|||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class NotesAndAchievements(BaseModel):
|
||||
notes: list
|
||||
achievements: list
|
||||
|
||||
|
||||
class Note(BaseModel):
|
||||
date: str
|
||||
teacher: str
|
||||
category: str
|
||||
content: str
|
||||
points: Optional[str]
|
||||
show_points: bool = False
|
||||
category_type: int = 0
|
|
@ -1,21 +0,0 @@
|
|||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class Login(BaseModel):
|
||||
username: str
|
||||
password: str
|
||||
symbol: str
|
||||
host: str
|
||||
ssl: Optional[bool]
|
||||
|
||||
|
||||
class UonetPlusUczen(BaseModel):
|
||||
host: str
|
||||
symbol: str
|
||||
school_id: str
|
||||
ssl: bool
|
||||
headers: object
|
||||
student: object
|
||||
vulcan_cookies: object
|
||||
payload: Optional[dict]
|
|
@ -1,19 +0,0 @@
|
|||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class SchoolInfo(BaseModel):
|
||||
school: object
|
||||
teachers: list
|
||||
|
||||
|
||||
class School(BaseModel):
|
||||
name: str
|
||||
address: str
|
||||
contact: str
|
||||
headmaster: str
|
||||
pedagogue: str
|
||||
|
||||
|
||||
class Teacher(BaseModel):
|
||||
name: str
|
||||
subject: str
|
|
@ -1,38 +0,0 @@
|
|||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class Semester(BaseModel):
|
||||
number: int
|
||||
level: int
|
||||
start: datetime
|
||||
end: datetime
|
||||
class_id: int
|
||||
unit_id: int
|
||||
current: bool
|
||||
id: int
|
||||
|
||||
|
||||
class Student(BaseModel):
|
||||
id: int
|
||||
student_id: int
|
||||
student_name: str
|
||||
student_second_name: Optional[str]
|
||||
student_surname: str
|
||||
is_register: bool
|
||||
register_id: int
|
||||
kindergarten_register_id: int
|
||||
level: int
|
||||
symbol: str
|
||||
name: Optional[str]
|
||||
year: int
|
||||
start: datetime
|
||||
end: datetime
|
||||
full_name: str
|
||||
school_id: str
|
||||
school_name: str
|
||||
school_symbol: str
|
||||
cookies: object
|
||||
headers: object
|
||||
semesters: list
|
|
@ -1,30 +0,0 @@
|
|||
class CUFS:
|
||||
START: str = "/{SYMBOL}/Account/LogOn?ReturnUrl=%2F{SYMBOL}%2FFS%2FLS%3Fwa%3Dwsignin1.0%26wtrealm%3D{REALM}"
|
||||
LOGOUT: str = "/{SYMBOL}/FS/LS?wa=wsignout1.0"
|
||||
|
||||
|
||||
class UONETPLUS:
|
||||
START: str = "/{SYMBOL}/LoginEndpoint.aspx"
|
||||
GETKIDSLUCKYNUMBERS: str = "/{SYMBOL}/Start.mvc/GetKidsLuckyNumbers"
|
||||
GETSTUDENTDIRECTORINFORMATIONS: str = "/{SYMBOL}/Start.mvc/GetStudentDirectorInformations"
|
||||
|
||||
|
||||
class UZYTKOWNIK:
|
||||
NOWAWIADOMOSC_GETJEDNOSTKIUZYTKOWNIKA: str = (
|
||||
"/{SYMBOL}/NowaWiadomosc.mvc/GetJednostkiUzytkownika"
|
||||
)
|
||||
|
||||
|
||||
class UCZEN:
|
||||
START: str = "/{SYMBOL}/{SCHOOLID}/Start"
|
||||
UCZENDZIENNIK_GET: str = "/{SYMBOL}/{SCHOOLID}/UczenDziennik.mvc/Get"
|
||||
OCENY_GET: str = "/{SYMBOL}/{SCHOOLID}/Oceny.mvc/Get"
|
||||
STATYSTYKI_GETOCENYCZASTKOWE: str = "/{SYMBOL}/{SCHOOLID}/Statystyki.mvc/GetOcenyCzastkowe"
|
||||
UWAGIIOSIAGNIECIA_GET: str = "/{SYMBOL}/{SCHOOLID}/UwagiIOsiagniecia.mvc/Get"
|
||||
ZEBRANIA_GET: str = "/{SYMBOL}/{SCHOOLID}/Zebrania.mvc/Get"
|
||||
SZKOLAINAUCZYCIELE_GET: str = "/{SYMBOL}/{SCHOOLID}/SzkolaINauczyciele.mvc/Get"
|
||||
ZAREJESTROWANEURZADZENIA_GET: str = "/{SYMBOL}/{SCHOOLID}/ZarejestrowaneUrzadzenia.mvc/Get"
|
||||
ZAREJESTROWANEURZADZENIA_DELETE: str = (
|
||||
"/{SYMBOL}/{SCHOOLID}/ZarejestrowaneUrzadzenia.mvc/Delete"
|
||||
)
|
||||
REJESTRACJAURZADZENIATOKEN_GET: str = "/{SYMBOL}/{SCHOOLID}/RejestracjaUrzadzeniaToken.mvc/Get"
|
|
@ -1,25 +0,0 @@
|
|||
import uvicorn
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from app.endpoints import login, uonetplus_uczen
|
||||
|
||||
app = FastAPI(title="Uonetplus API")
|
||||
|
||||
app.include_router(login.router)
|
||||
app.include_router(uonetplus_uczen.router)
|
||||
|
||||
origins = [
|
||||
"http://localhost:8080",
|
||||
]
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=origins,
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
uvicorn.run("main:app", host="127.0.0.1", port=8000, reload=True)
|
|
@ -1,2 +0,0 @@
|
|||
[pytest]
|
||||
addopts = -s -v
|
|
@ -1,12 +0,0 @@
|
|||
beautifulsoup4
|
||||
bs4
|
||||
requests
|
||||
cryptography
|
||||
pytest
|
||||
pydantic~=1.9.0
|
||||
uvicorn~=0.17.5
|
||||
fastapi~=0.74.0
|
||||
starlette~=0.17.1
|
||||
lxml
|
||||
sty
|
||||
pytest-xdist
|
421
backend/test.py
|
@ -1,421 +0,0 @@
|
|||
from errno import errorcode
|
||||
from fastapi.testclient import TestClient
|
||||
from main import app
|
||||
import pytest
|
||||
import json
|
||||
import requests
|
||||
client = TestClient(app)
|
||||
class fg:
|
||||
lightgreen = "\x1B[38;5;46m"
|
||||
orange = "\x1B[38;5;208m"
|
||||
red = "\x1B[38;5;160m"
|
||||
rs = "\033[0m"
|
||||
|
||||
# Ustawienia dla wszystkich testów
|
||||
nick = "jan@fakelog.cf"
|
||||
password = "jan123"
|
||||
host = "fakelog.cf"
|
||||
backuphost = "fakelog.tk"
|
||||
symbol = "powiatwulkanowy"
|
||||
ssl = "false"
|
||||
# Ustawienia tygodni dla testów
|
||||
week_grades = "16"
|
||||
# Ustawienia id dla testów
|
||||
id_mobile_deleted = 1234
|
||||
# Ustawienia dla test_login_incorrect i test_symbol_incorrect
|
||||
nick_invalid = "jan@fakelog.cf"
|
||||
password_invalid = "Jan321"
|
||||
symbol_invalid = "warszawa"
|
||||
|
||||
|
||||
def status_check(status_check_code, status_check_json):
|
||||
if status_check_code == 200:
|
||||
status_check_response = print("\n" + fg.lightgreen + "OK " + str(status_check_code) + fg.rs)
|
||||
elif status_check_code == 111:
|
||||
status_check_response = print("\n" + fg.red + "Connection refused " + str(status_check_code) + fg.rs)
|
||||
elif status_check_code == 307:
|
||||
status_check_response = print("\n" + fg.orange + "Temporary redirect " + str(status_check_code) + fg.rs)
|
||||
elif status_check_code == 308:
|
||||
status_check_response = print("\n" + fg.orange + "Permanent redirect " + str(status_check_code) + fg.rs)
|
||||
elif status_check_code == 310:
|
||||
status_check_response = print("\n" + fg.red + "Too many redirects " + str(status_check_code) + fg.rs)
|
||||
elif status_check_code == 400:
|
||||
status_check_response = print("\n" + fg.red + "Bad Request " + str(status_check_code) + fg.rs)
|
||||
try:
|
||||
print(json.dumps(status_check_json, indent=4))
|
||||
except:
|
||||
print(status_check_json)
|
||||
elif status_check_code == 401:
|
||||
status_check_response = print("\n" + fg.red + "Unauthorized " + str(status_check_code) + fg.rs)
|
||||
elif status_check_code == 403:
|
||||
status_check_response = print("\n" + fg.red + "Forbidden " + str(status_check_code) + fg.rs)
|
||||
elif status_check_code == 404:
|
||||
status_check_response = print("\n" + fg.orange + "Not Found " + str(status_check_code) + fg.rs)
|
||||
elif status_check_code == 405:
|
||||
status_check_response = print("\n" + fg.orange + "Method Not Allowed " + str(status_check_code) + fg.rs)
|
||||
try:
|
||||
print(json.dumps(status_check_json, indent=4))
|
||||
except:
|
||||
print(status_check_json)
|
||||
elif status_check_code == 408:
|
||||
status_check_response = print("\n" + fg.orange + "Request Timeout " + str(status_check_code) + fg.rs)
|
||||
elif status_check_code == 422:
|
||||
status_check_response = print("\n" + fg.red + "Unprocessable Entity " + str(status_check_code) + fg.rs)
|
||||
try:
|
||||
print(json.dumps(status_check_json, indent=4))
|
||||
except:
|
||||
print(status_check_json)
|
||||
elif status_check_code == 429:
|
||||
status_check_response = print("\n" + fg.red + "Too Many Requests " + str(status_check_code) + fg.rs)
|
||||
elif status_check_code == 500:
|
||||
status_check_response = print("\n" + fg.red + "Internal Server Error " + str(status_check_code) + fg.rs)
|
||||
elif status_check_code == 502:
|
||||
status_check_response = print("\n" + fg.orange + "Bad Gateway " + str(status_check_code) + fg.rs)
|
||||
elif status_check_code == 503:
|
||||
status_check_response = print("\n" + fg.orange + "Service Unavailable " + str(status_check_code) + fg.rs)
|
||||
elif status_check_code == 504:
|
||||
status_check_response = print("\n" + fg.orange + "Gateway Timeout " + str(status_check_code) + fg.rs)
|
||||
elif status_check_code == 505:
|
||||
status_check_response = print("\n" + fg.orange + "HTTP Version Not Supported " + str(status_check_code) + fg.rs)
|
||||
elif status_check_code == 521:
|
||||
status_check_response = print("\n" + fg.red + "Web server is down " + str(status_check_code) + fg.rs)
|
||||
elif status_check_code == 522:
|
||||
status_check_response = print("\n" + fg.red + "Connection timed out " + str(status_check_code) + fg.rs)
|
||||
elif status_check_code == 525:
|
||||
status_check_response = print("\n" + fg.red + "SSL Handshake Failed " + str(status_check_code) + fg.rs)
|
||||
elif status_check_code == 526:
|
||||
status_check_response = print("\n" + fg.red + "Invalid SSL Certificate " + str(status_check_code) + fg.rs)
|
||||
try:
|
||||
return status_check_response, status_check_json
|
||||
except:
|
||||
return status_check_response
|
||||
|
||||
|
||||
def test_check_connection():
|
||||
if ssl == "true":
|
||||
check = requests.get(
|
||||
"https://fakelog.cf",
|
||||
)
|
||||
elif ssl == "false":
|
||||
check = requests.get(
|
||||
"http://fakelog.cf",
|
||||
)
|
||||
status_check(check.status_code, check.json)
|
||||
if check.status_code == 503 or check.status_code == 521 or check.status_code == 522 or check.status_code == 525 or check.status_code == 526 or check.status_code == 429 or check.status_code == 408 or check.status_code == 500 or check.status_code == 502 or check.status_code == 504 or check.status_code == 111:
|
||||
global host
|
||||
host = backuphost
|
||||
print(fg.orange + "Main host unavailable. Changed to backup host" + fg.rs)
|
||||
|
||||
|
||||
def test_login_correct():
|
||||
global cookies, headars, student, school_id, errorcode
|
||||
login = client.post(
|
||||
"/login",
|
||||
headers={"Content-Type": "application/json"},
|
||||
json={
|
||||
"username": nick,
|
||||
"password": password,
|
||||
"host": host,
|
||||
"symbol": symbol,
|
||||
"ssl": ssl,
|
||||
},
|
||||
)
|
||||
cookies = login.json()["vulcan_cookies"]
|
||||
headars = login.json()["students"][0]["headers"]
|
||||
student = login.json()["students"][0]["cookies"]
|
||||
school_id = login.json()["students"][0]["school_id"]
|
||||
# print(login.json())
|
||||
if login.status_code == 200:
|
||||
print("\n" + fg.lightgreen + "OK " + str(login.status_code) + fg.rs)
|
||||
assert login.json()["symbol"] == "powiatwulkanowy"
|
||||
try:
|
||||
assert login.json()["host"] == "fakelog.cf"
|
||||
except:
|
||||
assert login.json()["host"] == "fakelog.tk"
|
||||
if not cookies:
|
||||
errorcode = 1
|
||||
print("\nCookies output: ")
|
||||
print(login.json()["vulcan_cookies"])
|
||||
pytest.fail("No VULCAN cookies detected")
|
||||
elif not headars:
|
||||
errorcode = 2
|
||||
print("\nHeaders output: ")
|
||||
print(login.json()["students"][0]["headers"])
|
||||
pytest.fail("No headers detected")
|
||||
elif not student:
|
||||
errorcode = 3
|
||||
print("\nStudent output: ")
|
||||
print(login.json()["students"][0]["cookies"])
|
||||
pytest.fail("No student cookies detected")
|
||||
elif not school_id:
|
||||
errorcode = 4
|
||||
print("\nSchool ID output: ")
|
||||
print(login.json()["students"][0]["school_id"])
|
||||
pytest.fail("No school ID detected")
|
||||
|
||||
|
||||
def test_login_incorrect():
|
||||
if errorcode == 1:
|
||||
pytest.skip("Skipped due to no cookies detected")
|
||||
elif errorcode == 2:
|
||||
pytest.skip("Skipped due to no headers detected")
|
||||
elif errorcode == 3:
|
||||
pytest.skip("Skipped due to no student cookies detected")
|
||||
elif errorcode == 4:
|
||||
pytest.skip("Skipped due to no school ID detected")
|
||||
response = client.post(
|
||||
"/login",
|
||||
headers={"Content-Type": "application/json"},
|
||||
json={
|
||||
"username": nick_invalid,
|
||||
"password": password_invalid,
|
||||
"host": host,
|
||||
"symbol": symbol,
|
||||
"ssl": ssl,
|
||||
"json": {},
|
||||
"headers": headars,
|
||||
},
|
||||
)
|
||||
status_check(response.status_code, response.json())
|
||||
assert response.json() == {'detail': 'Username or password is incorrect'}
|
||||
|
||||
|
||||
def test_symbol_incorrect():
|
||||
if errorcode == 1:
|
||||
pytest.skip("Skipped due to no cookies detected")
|
||||
elif errorcode == 2:
|
||||
pytest.skip("Skipped due to no headers detected")
|
||||
elif errorcode == 3:
|
||||
pytest.skip("Skipped due to no student cookies detected")
|
||||
elif errorcode == 4:
|
||||
pytest.skip("Skipped due to no school ID detected")
|
||||
response = client.post(
|
||||
"/login",
|
||||
headers={"Content-Type": "application/json"},
|
||||
json={
|
||||
"username": nick,
|
||||
"password": password,
|
||||
"host": host,
|
||||
"symbol": symbol_invalid,
|
||||
"ssl": ssl,
|
||||
"json": {},
|
||||
"headers": headars,
|
||||
},
|
||||
)
|
||||
status_check(response.status_code, response.json())
|
||||
assert response.json() == {"detail": "Symbol is incorrect"}
|
||||
|
||||
|
||||
def test_notes():
|
||||
if errorcode == 1:
|
||||
pytest.skip("Skipped due to no cookies detected")
|
||||
elif errorcode == 2:
|
||||
pytest.skip("Skipped due to no headers detected")
|
||||
elif errorcode == 3:
|
||||
pytest.skip("Skipped due to no student cookies detected")
|
||||
elif errorcode == 4:
|
||||
pytest.skip("Skipped due to no school ID detected")
|
||||
response = client.post(
|
||||
"/uonetplus-uczen/notes",
|
||||
headers={"Content-Type": "application/json"},
|
||||
json={
|
||||
"vulcan_cookies": cookies,
|
||||
"student": student,
|
||||
"school_id": school_id,
|
||||
"host": host,
|
||||
"symbol": symbol,
|
||||
"ssl": ssl,
|
||||
"json": {},
|
||||
"headers": headars,
|
||||
},
|
||||
)
|
||||
status_check(response.status_code, response.json())
|
||||
assert response.json()["notes"][0]["teacher"] == "Karolina Kowalska [AN]"
|
||||
assert response.json()["notes"][1]["content"] == "+ 20p za udział w Konkursie Języka Angielskiego"
|
||||
#print(response.json())
|
||||
|
||||
|
||||
def test_grades():
|
||||
if errorcode == 1:
|
||||
pytest.skip("Skipped due to no cookies detected")
|
||||
elif errorcode == 2:
|
||||
pytest.skip("Skipped due to no headers detected")
|
||||
elif errorcode == 3:
|
||||
pytest.skip("Skipped due to no student cookies detected")
|
||||
elif errorcode == 4:
|
||||
pytest.skip("Skipped due to no school ID detected")
|
||||
response = client.post(
|
||||
"/uonetplus-uczen/grades",
|
||||
headers={"Content-Type": "application/json"},
|
||||
json={
|
||||
"vulcan_cookies": cookies,
|
||||
"student": student,
|
||||
"school_id": school_id,
|
||||
"host": host,
|
||||
"symbol": symbol,
|
||||
"ssl": ssl,
|
||||
"json": {"okres": week_grades},
|
||||
"headers": headars,
|
||||
},
|
||||
)
|
||||
status_check(response.status_code, response.json())
|
||||
assert response.json()["subjects"][0]["grades"][0]["teacher"] == "Karolina Kowalska"
|
||||
assert response.json()["subjects"][0]["grades"][0]["symbol"] == "Akt"
|
||||
# print(response.json())
|
||||
# assert response.json()['grades'][3]['grade'] == '4'
|
||||
|
||||
|
||||
def test_school_info():
|
||||
if errorcode == 1:
|
||||
pytest.skip("Skipped due to no cookies detected")
|
||||
elif errorcode == 2:
|
||||
pytest.skip("Skipped due to no headers detected")
|
||||
elif errorcode == 3:
|
||||
pytest.skip("Skipped due to no student cookies detected")
|
||||
elif errorcode == 4:
|
||||
pytest.skip("Skipped due to no school ID detected")
|
||||
response = client.post(
|
||||
"/uonetplus-uczen/school-info",
|
||||
headers={"Content-Type": "application/json"},
|
||||
json={
|
||||
"vulcan_cookies": cookies,
|
||||
"student": student,
|
||||
"school_id": school_id,
|
||||
"host": host,
|
||||
"symbol": symbol,
|
||||
"ssl": ssl,
|
||||
"json": {},
|
||||
"headers": headars,
|
||||
},
|
||||
)
|
||||
status_check(response.status_code, response.json())
|
||||
assert (
|
||||
response.json()["school"]["name"]
|
||||
== "Publiczna szkoła Wulkanowego nr 1 w fakelog.cf"
|
||||
)
|
||||
assert response.json()["teachers"][0]["name"] == "Karolina Kowalska [AN]"
|
||||
# print(response.json())
|
||||
|
||||
|
||||
def test_conference():
|
||||
if errorcode == 1:
|
||||
pytest.skip("Skipped due to no cookies detected")
|
||||
elif errorcode == 2:
|
||||
pytest.skip("Skipped due to no headers detected")
|
||||
elif errorcode == 3:
|
||||
pytest.skip("Skipped due to no student cookies detected")
|
||||
elif errorcode == 4:
|
||||
pytest.skip("Skipped due to no school ID detected")
|
||||
response = client.post(
|
||||
"/uonetplus-uczen/conferences",
|
||||
headers={"Content-Type": "application/json"},
|
||||
json={
|
||||
"vulcan_cookies": cookies,
|
||||
"student": student,
|
||||
"school_id": school_id,
|
||||
"host": host,
|
||||
"symbol": symbol,
|
||||
"ssl": ssl,
|
||||
"json": {},
|
||||
"headers": headars,
|
||||
},
|
||||
)
|
||||
status_check(response.status_code, response.json())
|
||||
assert (
|
||||
response.json()[0]["subject"]
|
||||
== "Podsumowanie I semestru - średnia klasy, oceny, frekwencja, zachowanie."
|
||||
)
|
||||
assert response.json()[1]["date"] == "06.09.2019 16:30"
|
||||
# print(response.json())
|
||||
|
||||
|
||||
def test_mobile_access_registed():
|
||||
if errorcode == 1:
|
||||
pytest.skip("Skipped due to no cookies detected")
|
||||
elif errorcode == 2:
|
||||
pytest.skip("Skipped due to no headers detected")
|
||||
elif errorcode == 3:
|
||||
pytest.skip("Skipped due to no student cookies detected")
|
||||
elif errorcode == 4:
|
||||
pytest.skip("Skipped due to no school ID detected")
|
||||
response = client.post(
|
||||
"/uonetplus-uczen/mobile-access/get-registered-devices",
|
||||
headers={"Content-Type": "application/json"},
|
||||
json={
|
||||
"vulcan_cookies": cookies,
|
||||
"student": student,
|
||||
"school_id": school_id,
|
||||
"host": host,
|
||||
"symbol": symbol,
|
||||
"ssl": ssl,
|
||||
"json": {},
|
||||
"headers": headars,
|
||||
},
|
||||
)
|
||||
status_check(response.status_code, response.json())
|
||||
assert (
|
||||
response.json()[0]["name"]
|
||||
== "To Be Filled By O.E.M.#To Be Filled By O.E.M. (Windows 8.1)"
|
||||
)
|
||||
assert response.json()[1]["id"] == 1234
|
||||
# print(response.json())
|
||||
|
||||
|
||||
def test_mobile_access_register():
|
||||
if errorcode == 1:
|
||||
pytest.skip("Skipped due to no cookies detected")
|
||||
elif errorcode == 2:
|
||||
pytest.skip("Skipped due to no headers detected")
|
||||
elif errorcode == 3:
|
||||
pytest.skip("Skipped due to no student cookies detected")
|
||||
elif errorcode == 4:
|
||||
pytest.skip("Skipped due to no school ID detected")
|
||||
response = client.post(
|
||||
"/uonetplus-uczen/mobile-access/register-device",
|
||||
headers={"Content-Type": "application/json"},
|
||||
json={
|
||||
"vulcan_cookies": cookies,
|
||||
"student": student,
|
||||
"school_id": school_id,
|
||||
"host": host,
|
||||
"symbol": symbol,
|
||||
"ssl": ssl,
|
||||
},
|
||||
)
|
||||
status_check(response.status_code, response.json())
|
||||
assert response.json()["pin"] == "999999"
|
||||
assert response.json()["qr_code_image"]
|
||||
# print(response.json())
|
||||
|
||||
|
||||
def test_mobile_access_delete_registed():
|
||||
if errorcode == 1:
|
||||
pytest.skip("Skipped due to no cookies detected")
|
||||
elif errorcode == 2:
|
||||
pytest.skip("Skipped due to no headers detected")
|
||||
elif errorcode == 3:
|
||||
pytest.skip("Skipped due to no student cookies detected")
|
||||
elif errorcode == 4:
|
||||
pytest.skip("Skipped due to no school ID detected")
|
||||
response = client.post(
|
||||
"/uonetplus-uczen/mobile-access/delete-registered-device",
|
||||
headers={"Content-Type": "application/json"},
|
||||
json={
|
||||
"vulcan_cookies": cookies,
|
||||
"student": student,
|
||||
"school_id": school_id,
|
||||
"host": host,
|
||||
"symbol": symbol,
|
||||
"ssl": ssl,
|
||||
"json": {"id": id_mobile_deleted},
|
||||
"headers": headars,
|
||||
},
|
||||
)
|
||||
status_check(response.status_code, response.json())
|
||||
# Nowa metoda testowania
|
||||
# if response.status_code == 404:
|
||||
# print(response.json())
|
||||
# else:
|
||||
# print("Test")
|
||||
assert response.json()["success"] == True
|
||||
# print(response.json())
|
|
@ -3,17 +3,24 @@ module.exports = {
|
|||
env: {
|
||||
node: true,
|
||||
},
|
||||
extends: ["plugin:vue/essential", "eslint:recommended", "@vue/typescript/recommended"],
|
||||
extends: [
|
||||
'plugin:vue/essential',
|
||||
'@vue/airbnb',
|
||||
'@vue/typescript/recommended',
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 2020,
|
||||
},
|
||||
rules: {
|
||||
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
|
||||
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ["**/__tests__/*.{j,t}s?(x)", "**/tests/unit/**/*.spec.{j,t}s?(x)"],
|
||||
files: [
|
||||
'**/__tests__/*.{j,t}s?(x)',
|
||||
'**/tests/unit/**/*.spec.{j,t}s?(x)',
|
||||
],
|
||||
env: {
|
||||
mocha: true,
|
||||
},
|
||||
|
|
1
frontend/.gitignore
vendored
|
@ -24,4 +24,3 @@ pnpm-debug.log*
|
|||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
|
|
|
@ -1,13 +1,34 @@
|
|||
# Wulkanowy Web Frontend
|
||||
# frontend
|
||||
|
||||
## 1. Install dependencies
|
||||
|
||||
```sh
|
||||
## Project setup
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
## 2. Start the server
|
||||
|
||||
```sh
|
||||
### Compiles and hot-reloads for development
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Run your unit tests
|
||||
```
|
||||
npm run test:unit
|
||||
```
|
||||
|
||||
### Run your end-to-end tests
|
||||
```
|
||||
npm run test:e2e
|
||||
```
|
||||
|
||||
### Lints and fixes files
|
||||
```
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### Customize configuration
|
||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
||||
|
|
0
frontend/__init__.py
Normal file
3
frontend/admin.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
5
frontend/apps.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class FrontendConfig(AppConfig):
|
||||
name = 'frontend'
|
5
frontend/babel.config.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset',
|
||||
],
|
||||
};
|
3
frontend/cypress.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"pluginsFile": "tests/e2e/plugins/index.js"
|
||||
}
|
0
frontend/migrations/__init__.py
Normal file
3
frontend/models.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
29396
frontend/package-lock.json
generated
|
@ -3,17 +3,20 @@
|
|||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve --openssl-legacy-provider",
|
||||
"build": "vue-cli-service build --openssl-legacy-provider",
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"test:unit": "vue-cli-service test:unit",
|
||||
"test:e2e": "vue-cli-service test:e2e",
|
||||
"lint": "vue-cli-service lint --openssl-legacy-provider"
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.26.1",
|
||||
"axios": "^0.21.1",
|
||||
"core-js": "^3.6.5",
|
||||
"register-service-worker": "^1.7.1",
|
||||
"universal-cookie": "^4.0.4",
|
||||
"vue": "^2.6.11",
|
||||
"vue-router": "^3.2.0",
|
||||
"vuetify": "^2.6.4",
|
||||
"vuetify": "^2.4.0",
|
||||
"vuex": "^3.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -21,26 +24,28 @@
|
|||
"@types/mocha": "^5.2.4",
|
||||
"@typescript-eslint/eslint-plugin": "^4.18.0",
|
||||
"@typescript-eslint/parser": "^4.18.0",
|
||||
"@vue/cli-plugin-e2e-cypress": "~4.5.13",
|
||||
"@vue/cli-plugin-eslint": "~4.5.13",
|
||||
"@vue/cli-plugin-router": "~4.5.13",
|
||||
"@vue/cli-plugin-typescript": "~4.5.13",
|
||||
"@vue/cli-plugin-unit-mocha": "~4.5.13",
|
||||
"@vue/cli-plugin-vuex": "~4.5.13",
|
||||
"@vue/cli-service": "~4.5.13",
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
"@vue/cli-plugin-e2e-cypress": "~4.5.0",
|
||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||
"@vue/cli-plugin-pwa": "~4.5.0",
|
||||
"@vue/cli-plugin-router": "~4.5.0",
|
||||
"@vue/cli-plugin-typescript": "~4.5.0",
|
||||
"@vue/cli-plugin-unit-mocha": "~4.5.0",
|
||||
"@vue/cli-plugin-vuex": "~4.5.0",
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"@vue/eslint-config-airbnb": "^5.0.2",
|
||||
"@vue/eslint-config-typescript": "^7.0.0",
|
||||
"@vue/test-utils": "^1.0.3",
|
||||
"chai": "^4.1.2",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"sass": "~1.32.0",
|
||||
"node-sass": "^4.12.0",
|
||||
"sass": "^1.32.0",
|
||||
"sass-loader": "^10.0.0",
|
||||
"typescript": "~4.1.5",
|
||||
"vue-cli-plugin-vuetify": "~2.4.8",
|
||||
"vue-cli-plugin-vuetify": "~2.3.1",
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
"vuetify-loader": "^1.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "16.x"
|
||||
}
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 4.2 KiB |
|
@ -1,26 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
|
||||
<title>Wulkanowy</title>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css"
|
||||
/>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:400,500,700,400italic|Material+Icons">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong
|
||||
>We're sorry but Wulkanowy doesn't work properly without JavaScript
|
||||
enabled. Please enable it to continue.</strong
|
||||
>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
|
|
|
@ -1,46 +1,13 @@
|
|||
<template>
|
||||
<v-app>
|
||||
<router-view />
|
||||
<router-view></router-view>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import Vue from 'vue';
|
||||
|
||||
export default Vue.extend({
|
||||
name: "App",
|
||||
|
||||
beforeMount() {
|
||||
let darkTheme = localStorage.getItem("dark_theme");
|
||||
if (darkTheme) {
|
||||
if (darkTheme == "true") {
|
||||
this.$vuetify.theme.dark = true;
|
||||
} else {
|
||||
this.$vuetify.theme.dark = false;
|
||||
}
|
||||
} else {
|
||||
localStorage.setItem("dark_theme", "false");
|
||||
}
|
||||
},
|
||||
created() {
|
||||
window.addEventListener("resize", this.handleResize);
|
||||
this.handleResize();
|
||||
},
|
||||
destroyed() {
|
||||
window.removeEventListener("resize", this.handleResize);
|
||||
},
|
||||
methods: {
|
||||
handleResize() {
|
||||
const screen_width = window.innerWidth;
|
||||
this.$store.state.small_ui = screen_width < 1264;
|
||||
},
|
||||
},
|
||||
name: 'App',
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.v-card__text,
|
||||
.v-card__title {
|
||||
word-break: normal !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
import axios from 'axios';
|
||||
import store from '@/store/index';
|
||||
|
||||
export default {
|
||||
login: async (username: string, password: string, symbol: string, host: string, ssl: boolean) => {
|
||||
const response: any = await axios({
|
||||
method: 'POST',
|
||||
url: 'http://localhost:8000/login',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
data: {
|
||||
username,
|
||||
password,
|
||||
symbol,
|
||||
host,
|
||||
ssl,
|
||||
},
|
||||
withCredentials: true,
|
||||
})
|
||||
.catch(function (error: any) {
|
||||
if(error.toJSON().message == 'Network Error'){
|
||||
store.state.error.description = 'No internet connection';
|
||||
store.state.error.details = error.toJSON().stack;
|
||||
store.state.error.show = true;
|
||||
store.state.loading = false;
|
||||
} else {
|
||||
store.state.error.description = error.response.data.detail;
|
||||
store.state.error.details = error.toJSON().stack;
|
||||
store.state.error.show = true;
|
||||
store.state.loading = false;
|
||||
}
|
||||
});
|
||||
if (!response.data.students.length) {
|
||||
store.state.error.description = 'This account have not any students';
|
||||
store.state.error.show = true;
|
||||
store.state.loading = false;
|
||||
return null;
|
||||
} else {
|
||||
store.state.logged_in = true;
|
||||
store.state.loading = false;
|
||||
return response;
|
||||
}
|
||||
},
|
||||
};
|
27
frontend/src/api/login.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import axios, { AxiosResponse } from 'axios';
|
||||
import Cookies from 'universal-cookie';
|
||||
|
||||
export default {
|
||||
login: async (email: string, password: string, symbol: string, diaryUrl: string)
|
||||
: Promise<AxiosResponse> => {
|
||||
const cookies = new Cookies();
|
||||
const response = await axios({
|
||||
method: 'POST',
|
||||
url: 'http://localhost:8000/api/login',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': cookies.get('csrftoken'),
|
||||
},
|
||||
data: {
|
||||
loginName: email,
|
||||
Password: password,
|
||||
Symbol: symbol,
|
||||
diaryUrl,
|
||||
},
|
||||
withCredentials: true,
|
||||
});
|
||||
|
||||
document.cookie = response.headers['Set-Cookie'];
|
||||
return response;
|
||||
},
|
||||
};
|
12
frontend/src/assets/data/diary.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"diaries": [
|
||||
{
|
||||
"name": "Vulcan",
|
||||
"url": "https://cufs.vulcan.net.pl/"
|
||||
},
|
||||
{
|
||||
"name": "Fakelog",
|
||||
"url": "http://cufs.fakelog.tk/"
|
||||
}
|
||||
]
|
||||
}
|
129
frontend/src/assets/logo_login.svg
Normal file
|
@ -0,0 +1,129 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
height="1024"
|
||||
width="3584"
|
||||
xml:space="preserve"
|
||||
viewBox="0 0 3584 1024"
|
||||
y="0px"
|
||||
x="0px"
|
||||
id="Layer_1"
|
||||
version="1.1"
|
||||
sodipodi:docname="wulkanowy-full-flat.svg"
|
||||
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
id="namedview25"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.33928571"
|
||||
inkscape:cx="1860.4549"
|
||||
inkscape:cy="586.56969"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="text8460" /><metadata
|
||||
id="metadata15"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs13" /><style
|
||||
id="style2"
|
||||
type="text/css">
|
||||
.st0{fill:#D32F2F;}
|
||||
.st1{fill:#AD2A2A;}
|
||||
.st2{fill:#FFFFFF;}
|
||||
</style><g
|
||||
style="display:none"
|
||||
id="layer4"><rect
|
||||
style="display:inline;fill:#d32f2f;stroke-width:1.02195609"
|
||||
height="1024"
|
||||
width="3584"
|
||||
class="st0"
|
||||
y="0"
|
||||
x="0"
|
||||
id="XMLID_57_" /></g><g
|
||||
style="display:none"
|
||||
id="layer3"><path
|
||||
id="path18992"
|
||||
d="M 3046.8164,390.66602 3134.3164,542 v 91.33398 L 3524.9824,1024 H 3584 V 732.18359 L 3242.4824,390.66602 h -23.666 l -53.0352,94.63086 -94.6308,-94.63086 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;display:inline;fill:#ad2a2a;fill-opacity:1;stroke:none" /><path
|
||||
id="path18990"
|
||||
d="m 2746.9824,390.66602 62,242.66796 L 3199.6484,1024 H 3584 V 940.68359 L 3033.9824,390.66602 h -21 l -21.9043,90.92773 -90.9277,-90.92773 h -18.5 l -25.4043,88.26367 -88.2637,-88.26367 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;display:inline;fill:#ad2a2a;fill-opacity:1;stroke:none" /><path
|
||||
id="path18988"
|
||||
d="m 2620.8164,387.33398 c -18.6667,0 -35.1667,4.60982 -49.5,13.83204 -14.3333,9.11111 -25.4451,22.22287 -33.334,39.33398 -7.7778,17 -11.666,36.5549 -11.666,58.66602 v 25 c 0,34.44444 8.7216,61.83463 26.166,82.16796 L 2970.1484,1024 h 323.168 l -623.166,-623.16602 c -14.2222,-9 -30.6673,-13.5 -49.334,-13.5 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;display:inline;fill:#ad2a2a;fill-opacity:1;stroke:none" /><path
|
||||
id="path18984"
|
||||
d="M 2293.4824,390.66602 V 633.33398 L 2684.1484,1024 h 423.336 l -633.334,-633.33398 h -20.334 v 139.66601 l -139.666,-139.66601 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;display:inline;fill:#ad2a2a;fill-opacity:1;stroke:none" /><path
|
||||
id="path18978"
|
||||
d="M 1864.8164,390.66602 V 633.33398 L 2255.4824,1024 h 413.334 l -633.334,-633.33398 h -25.832 l -60.584,63.75 -63.75,-63.75 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;display:inline;fill:#ad2a2a;fill-opacity:1;stroke:none" /><path
|
||||
id="path18976"
|
||||
d="M 1684.8164,390.66602 V 633.33398 L 2075.4824,1024 h 263.334 l -633.334,-633.33398 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;display:inline;fill:#ad2a2a;fill-opacity:1;stroke:none" /><path
|
||||
id="path19059"
|
||||
d="m 1133.6504,390.66602 62,242.66796 L 1586.3164,1024 h 467.668 l -633.334,-633.33398 h -21 l -21.9043,90.92773 -90.9277,-90.92773 h -18.5 l -25.4043,88.26367 -88.2637,-88.26367 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;display:inline;fill:#ad2a2a;fill-opacity:1;stroke:none" /><path
|
||||
id="path18966"
|
||||
d="m 1456.4824,390.66602 v 167.16796 c 0.5556,24.66667 8.5007,44 23.834,58 L 1888.4824,1024 h 372.168 l -633.334,-633.33398 h -20.666 V 520.5 l -129.834,-129.83398 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;display:inline;fill:#ad2a2a;fill-opacity:1;stroke:none" /><path
|
||||
id="path18982"
|
||||
d="M 2146.3164,390.66602 2054.4824,633.33398 2445.1484,1024 h 354.002 l -633.334,-633.33398 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;display:inline;fill:#ad2a2a;fill-opacity:1;stroke:none" /><path
|
||||
id="XMLID_64_"
|
||||
d="M 637.15234,214.95703 487.75,364.35742 466.01562,386.0918 c 0.31273,0.31271 0.54872,0.54666 0.70508,0.85937 0.0782,0.23454 0.23432,0.54671 0.3125,0.78125 0.31272,0.54726 0.47071,1.17339 0.47071,1.79883 0.0782,0.54726 -0.0799,1.01725 -0.31446,1.48633 -0.23454,0.54725 -0.70285,1.40597 -1.09375,1.79687 l 150.8086,149.71485 -23.68946,23.6875 -12.74414,-12.74219 -13.44726,-13.44727 -78.80469,-78.80664 -11.17969,-11.17968 -7.5039,-7.50391 -35.41602,-35.17969 -3.08984,-0.98047 -4.33594,4.26367 v 0.46876 c 0,7.34888 0.38998,15.00865 -1.48633,22.20117 -0.85998,3.28355 -2.34444,6.25595 -4.14258,8.91406 -0.15636,0.15636 -0.23627,0.23426 -0.31445,0.39062 -1.87631,2.57993 -4.06471,4.84619 -6.48828,6.95704 -5.3944,4.53442 -11.25752,8.67896 -17.27734,12.50976 -0.15637,0.0782 -0.23427,0.1562 -0.39063,0.23438 -2.11085,1.40723 -4.3012,2.7354 -6.49023,4.06445 -8.91248,5.39439 -18.37192,10.08772 -28.37891,13.13672 -1.25087,0.31272 -2.42317,-0.001 -3.36133,-0.70508 l -6.01953,5.94141 c 1.25087,0.62543 2.03136,1.87776 1.875,3.51953 -10e-6,0.15636 -0.0762,0.23231 -0.0762,0.38867 0,0.0782 -0.0781,0.23628 -0.0781,0.31445 -1.32905,4.45624 -2.34505,8.98897 -3.2832,13.60156 -0.15636,0.70363 -0.23622,1.33154 -0.39258,2.03516 -0.85997,4.37806 -1.64209,8.83288 -2.3457,13.21094 0.23453,5.3944 0.39263,11.0234 0.31445,16.65234 v 0.39258 c -0.0782,7.66161 -0.78373,15.32114 -2.8164,22.51367 -2.26721,8.28704 -6.64376,15.63728 -10.55274,23.22071 -0.0782,0.15636 -0.15815,0.23426 -0.23633,0.39062 -1.25088,2.42357 -2.49924,4.92399 -3.59375,7.50391 -4.84714,11.33605 -7.42749,23.92328 -10.55468,35.88476 -0.23454,0.70362 -0.39046,1.48578 -0.625,2.26758 0,0.15636 -0.0801,0.23427 -0.0801,0.39063 -2.97082,11.10151 -6.09819,22.28173 -10.94532,32.75781 -1.40724,2.97082 -2.81531,5.86322 -4.3789,8.75586 -0.15636,0.23454 -0.23231,0.46858 -0.38867,0.70312 -0.62544,1.09451 -1.25152,2.26871 -1.87696,3.44141 -0.0782,0.15636 -0.15619,0.23426 -0.23437,0.39062 -3.51809,6.25438 -7.27098,12.43118 -10.78906,18.68555 -5.0035,8.8343 -8.99075,18.13635 -13.83789,27.04883 -0.0782,0.15636 -0.1562,0.23426 -0.23438,0.39062 -0.70362,1.32905 -1.48579,2.65728 -2.26758,3.98633 -5.0035,8.20887 -10.63256,16.0279 -16.57422,23.61133 -0.15635,0.15636 -0.23426,0.3124 -0.39062,0.46875 -0.7818,1.01634 -1.48578,1.95443 -2.26758,2.89258 -3.90898,4.92532 -7.97378,9.85009 -11.96094,14.77539 -0.0782,0.15637 -0.23432,0.23622 -0.3125,0.39258 -8.75612,10.71061 -17.35628,21.49761 -24.54883,33.30273 0,0.70362 -0.15602,1.33159 -0.46874,1.95703 -1.25087,2.42357 -2.65734,4.68971 -3.90821,7.11328 -0.0782,0.15636 0.62511,1.24989 0.46875,1.40625 L 429.86133,1024 H 1463.0215 L 661.85547,222.92969 c -0.93816,2.11087 -5.23681,1.40935 -7.34766,-0.23242 -1.71995,-1.32906 -3.12603,-3.05147 -4.45508,-4.84961 -0.62544,-0.31271 -1.25168,-0.62288 -1.64257,-0.85743 -2.89265,-1.40723 -6.09933,-1.48632 -9.30469,-1.48632 -0.7818,-0.0782 -1.40588,-0.23416 -1.95313,-0.54688 z m -206.12304,191.41992 0.11914,-0.11523 -0.23438,0.0781 z"
|
||||
style="display:inline;fill:#ad2a2a;stroke-width:0.78179646" /></g><g
|
||||
style="display:inline"
|
||||
id="layer2"><path
|
||||
style="fill:#ffffff;stroke-width:0.78179646"
|
||||
d="m 385.17894,776.98989 c 0.62544,2.03267 0.31272,4.2217 -0.7818,6.01983 l -15.08867,24.47023 c -1.48541,2.42357 -4.2217,3.98716 -7.19253,3.98716 H 220.92351 c -6.56709,0 -10.55425,-6.8798 -7.03616,-12.03966 l 90.92292,-133.92173 c 0.54726,-0.78179 0.85997,-1.64177 1.09451,-2.50174 l 41.66975,-177.93687 c 0.46908,-2.11085 1.87631,-3.90898 3.90898,-5.00349 l 56.4457,-30.95914 c 2.03267,-1.09452 3.43991,-2.89265 3.90899,-5.08168 l 7.58342,-33.06999 c 1.56359,-6.8798 11.41423,-8.36522 15.32321,-2.34538 l 2.73629,4.37806 c 1.17269,1.87631 1.48541,4.2217 0.70362,6.33255 l -51.44221,148.69767 c -0.3909,1.1727 -0.54726,2.42357 -0.31272,3.67445 l 12.82146,71.14347 c 0.23454,1.40723 0.0782,2.89265 -0.54725,4.2217 l -30.56824,68.64172 c -0.70362,1.64178 -0.85998,3.43991 -0.31272,5.08168 z m 417.94836,34.47722 h -97.25548 c -2.81446,0 -5.39439,-1.40723 -6.95798,-3.59626 l -65.43636,-92.01744 c -0.3909,-0.62543 -0.7818,-1.25087 -1.01634,-1.95449 L 600.01659,619.1452 c -0.62544,-1.87631 -2.11085,-3.51809 -3.98716,-4.45624 L 516.59891,574.5828 c -2.18903,-1.09451 -3.75262,-3.12718 -4.2217,-5.39439 l -11.72694,-58.16566 c -0.15636,-0.93815 -0.54726,-1.87631 -1.1727,-2.73628 L 472.5056,468.64939 c -1.48542,-2.18903 -1.71995,-4.84714 -0.62544,-7.19253 l 16.41772,-35.10266 c 1.25088,-2.6581 3.98717,-4.45624 7.11435,-4.6126 l 30.49006,-1.79813 c 1.79813,-0.0782 3.43991,-0.70361 4.76896,-1.79813 l 22.43756,-17.43406 c 4.2217,-3.28354 10.63243,-1.87631 12.89964,2.73629 l 77.31966,157.29744 c 0.31272,0.70361 0.54726,1.40723 0.70362,2.11085 l 9.53792,63.24733 c 0.23453,1.48541 0.85997,2.81446 1.87631,3.90898 l 154.01389,168.5553 c 4.53442,5.0035 0.70362,12.89964 -6.33255,12.89964 z M 424.97238,319.32628 c 0,-17.90314 11.33604,-33.30453 27.59741,-40.49706 -1.1727,-1.95449 -1.87631,-4.06534 -1.87631,-6.33255 0,-8.67794 10.00699,-15.71411 22.2812,-15.71411 0.31271,0 0.54725,0 0.85997,0 5.08168,-8.4434 14.77595,-14.15051 25.87746,-14.15051 0.7818,0 1.5636,0 2.34539,0.0782 1.01634,0.0782 2.03267,-0.3909 2.57993,-1.1727 8.20886,-12.50874 29.00465,-21.42122 53.31851,-21.42122 8.99066,0 17.51224,1.25088 25.09567,3.36173 1.79813,-2.97083 5.78529,-5.0035 10.39789,-5.0035 5.23804,0 9.69428,2.65811 11.02333,6.33255 6.41073,-7.42707 17.2777,-12.2742 29.63008,-12.2742 19.70127,0 35.64992,12.43056 35.64992,27.75377 0,1.87631 -0.23454,3.67444 -0.70362,5.47257 -0.31271,1.25088 0.3909,2.50175 1.71996,2.97083 12.58692,4.6126 21.1085,13.36872 21.1085,23.37571 0,11.41423 -11.02333,21.18669 -26.58108,25.01749 -1.25087,0.31272 -2.03267,1.40723 -2.03267,2.57993 0,0.0782 0,0.15635 0,0.23453 0,8.8343 -8.75612,16.10501 -20.01399,16.88681 0.0782,0.3909 0.0782,0.78179 0.0782,1.25087 0,16.96498 -32.28819,30.64642 -72.08163,30.64642 -8.59976,0 -16.80862,-0.62544 -24.39204,-1.79813 0,0.15636 0,0.23454 0,0.3909 0,7.03616 -9.06884,12.74328 -20.17035,12.74328 -0.62544,0 -1.1727,0 -1.71995,-0.0782 0.78179,1.71995 1.17269,3.51808 1.17269,5.39439 0,10.94515 -13.8378,19.77945 -30.95914,19.77945 -1.87631,0 -3.67444,-0.0782 -5.47257,-0.31272 -1.40724,-0.15635 -2.73629,0.70362 -3.04901,2.03268 -1.48541,5.47257 -6.25437,9.45973 -11.96148,9.45973 -6.87981,0 -12.35239,-5.86347 -12.35239,-13.056 0,-3.36172 1.1727,-6.41073 3.12719,-8.67794 0.70362,-0.78179 0.93816,-1.87631 0.46908,-2.81447 -1.09452,-2.03267 -1.5636,-4.14352 -1.5636,-6.41073 v 0 c 0,-1.25087 -1.01633,-2.26721 -2.2672,-2.57992 -21.18669,-4.69078 -37.13533,-22.35938 -37.13533,-43.46788 z m 179.50045,424.6718 c 0.31272,0.93816 0.3909,1.87632 0.3909,2.89265 l -4.53442,57.30568 c -0.31272,4.06534 -3.90898,7.2707 -8.28704,7.2707 H 445.68998 c -3.12718,0 -6.01983,-1.79813 -7.42707,-4.37806 l -24.1575,-44.87511 c -0.15636,-0.23454 -0.23454,-0.46908 -0.31272,-0.70362 l -22.75028,-55.11664 c -0.85997,-1.95449 -0.70361,-4.2217 0.23454,-6.09802 l 37.76077,-73.87976 c 0.93815,-1.79813 1.09451,-3.90898 0.3909,-5.78529 l -18.4504,-51.12948 c -0.62544,-1.79814 -0.54726,-3.83081 0.23454,-5.55076 l 30.80278,-65.59272 c 3.12718,-6.56709 13.36872,-6.01983 15.55775,0.85998 l 9.61609,29.86462 29.31737,78.49236 c 0.78179,2.18903 2.6581,3.90898 5.00349,4.69078 l 62.54372,21.34304 c 2.42357,0.85998 4.29988,2.65811 5.08167,4.92532 z"
|
||||
id="XMLID_42_" /><g
|
||||
id="text4752"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
|
||||
aria-label="WULKANOWY" /></g><g
|
||||
style="display:inline"
|
||||
id="layer1"><g
|
||||
aria-label="WULKANOWY"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
|
||||
id="text8460"><path
|
||||
d="m 1198.9832,567.83331 7.5,37.66667 9.1666,-36 52.6667,-178.83334 h 18.5 l 52,178.83334 9,36.33333 8,-38 43.8333,-177.16667 h 21 l -62.1666,242.66667 h -19.6667 l -55,-189.83334 -6.1667,-24 -6,24 -56.3333,189.83334 h -19.6667 l -62,-242.66667 h 21 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;font-family:Roboto;-inkscape-font-specification:'Roboto Light';fill:#ffffff"
|
||||
id="path4764" /><path
|
||||
d="m 1627.3165,390.66664 v 165.66667 q -0.1667,24.5 -10.8333,42.66667 -10.6667,18.16667 -30.1667,28 -19.3333,9.66667 -44.5,9.66667 -38.3333,0 -61.5,-20.83334 -23,-21 -23.8333,-58 V 390.66664 h 20.3333 v 164.16667 q 0,30.66667 17.5,47.66667 17.5,16.83333 47.5,16.83333 30,0 47.3333,-17 17.5,-17 17.5,-47.33333 V 390.66664 Z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;font-family:Roboto;-inkscape-font-specification:'Roboto Light';fill:#ffffff"
|
||||
id="path4766" /><path
|
||||
d="m 1705.4832,615.99998 h 119.8333 v 17.33333 h -140.5 V 390.66664 h 20.6667 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;font-family:Roboto;-inkscape-font-specification:'Roboto Light';fill:#ffffff"
|
||||
id="path4768" /><path
|
||||
d="m 1919.4832,512.83331 -34.1667,33.66667 v 86.83333 h -20.5 V 390.66664 h 20.5 v 130.83334 l 124.3333,-130.83334 h 25.8334 l -101.6667,108 109.5,134.66667 h -25 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;font-family:Roboto;-inkscape-font-specification:'Roboto Light';fill:#ffffff"
|
||||
id="path4770" /><path
|
||||
d="m 2211.1498,565.33331 h -110.1666 l -25,68 h -21.5 l 91.8333,-242.66667 h 19.5 l 91.8333,242.66667 h -21.3333 z m -103.8333,-17.5 h 97.3333 l -48.6666,-132.16667 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;font-family:Roboto;-inkscape-font-specification:'Roboto Light';fill:#ffffff"
|
||||
id="path4772" /><path
|
||||
d="m 2474.1499,633.33331 h -20.5 l -139.5,-207.66667 v 207.66667 h -20.6667 V 390.66664 h 20.6667 l 139.6666,207.83334 V 390.66664 h 20.3334 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;font-family:Roboto;-inkscape-font-specification:'Roboto Light';fill:#ffffff"
|
||||
id="path4774" /><path
|
||||
d="m 2715.4832,525.16664 q 0,33.5 -11.6667,58.83334 -11.5,25.33333 -33,39 -21.5,13.66667 -49.6667,13.66667 -42.5,0 -68.6666,-30.33334 -26.1667,-30.5 -26.1667,-82.16667 v -25 q 0,-33.16667 11.6667,-58.66667 11.8333,-25.66666 33.3333,-39.33333 21.5,-13.83333 49.5,-13.83333 28,0 49.3333,13.5 21.5,13.5 33.1667,38.16666 11.6667,24.66667 12.1667,57.16667 z m -20.5,-26.33333 q 0,-43.83334 -19.8334,-68.66667 -19.8333,-24.83333 -54.3333,-24.83333 -33.8333,0 -54,25 -20,24.83333 -20,69.5 v 25.33333 q 0,43.16667 20,68.50001 20,25.16666 54.3333,25.16666 34.8334,0 54.3334,-24.83333 19.5,-25 19.5,-69.5 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;font-family:Roboto;-inkscape-font-specification:'Roboto Light';fill:#ffffff"
|
||||
id="path4776" /><path
|
||||
d="m 2812.3165,567.83331 7.5,37.66667 9.1667,-36 52.6667,-178.83334 h 18.5 l 52,178.83334 9,36.33333 8,-38 43.8333,-177.16667 h 21 l -62.1667,242.66667 h -19.6666 l -55,-189.83334 -6.1667,-24 -6,24 -56.3333,189.83334 h -19.6667 l -62,-242.66667 h 21 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;font-family:Roboto;-inkscape-font-specification:'Roboto Light';fill:#ffffff"
|
||||
id="path4778" /><path
|
||||
d="m 3144.6499,522.99998 74.1666,-132.33334 h 23.6667 l -87.6667,151.33334 v 91.33333 h -20.5 v -91.33333 l -87.5,-151.33334 h 24.3334 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;font-family:Roboto;-inkscape-font-specification:'Roboto Light';fill:#ffffff"
|
||||
id="path4780" /></g></g></svg>
|
After Width: | Height: | Size: 18 KiB |
|
@ -1,12 +0,0 @@
|
|||
[
|
||||
{
|
||||
"name": "Vulcan",
|
||||
"host": "vulcan.net.pl",
|
||||
"ssl": true
|
||||
},
|
||||
{
|
||||
"name": "Fakelog",
|
||||
"host": "fakelog.cf",
|
||||
"ssl": false
|
||||
}
|
||||
]
|
Before Width: | Height: | Size: 203 KiB After Width: | Height: | Size: 203 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
|
@ -1,84 +0,0 @@
|
|||
<template>
|
||||
<div id="baner" class="d-flex justify-center align-center fill-height flex-column">
|
||||
<img
|
||||
:src="`${
|
||||
this.$vuetify.theme.dark
|
||||
? require('../../assets/img/black_icon.svg')
|
||||
: require('../../assets/img/white_icon.svg')
|
||||
}`"
|
||||
width="140"
|
||||
/>
|
||||
<v-card-title
|
||||
:class="`text-center justify-center pa-2 headline ${
|
||||
this.$vuetify.theme.dark ? 'black--text' : 'white--text'
|
||||
}`"
|
||||
>
|
||||
Wulkanowy
|
||||
</v-card-title>
|
||||
<v-card-text
|
||||
:class="`${this.$vuetify.theme.dark ? 'black--text' : 'white--text'} text-center pa-2`"
|
||||
>
|
||||
Unofficial VULCAN UONET+ browser client for students and their parents
|
||||
</v-card-text>
|
||||
<v-card-subtitle
|
||||
:class="`text-center justify-center mt-6 ${
|
||||
this.$vuetify.theme.dark ? 'black--text' : 'white--text'
|
||||
}`"
|
||||
>
|
||||
<v-btn
|
||||
icon
|
||||
v-for="(item, i) in social"
|
||||
:key="i"
|
||||
:href="item.link"
|
||||
target="_blank"
|
||||
:light="$vuetify.theme.dark"
|
||||
:dark="!$vuetify.theme.dark"
|
||||
>
|
||||
<v-icon>{{ item.icon }}</v-icon>
|
||||
</v-btn>
|
||||
</v-card-subtitle>
|
||||
<v-card-subtitle
|
||||
:class="`text-center justify-center ${
|
||||
this.$vuetify.theme.dark ? 'black--text' : 'white--text'
|
||||
}`"
|
||||
>
|
||||
feature/add-new-backend-and-rewrite-login
|
||||
</v-card-subtitle>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
interface BanerData {
|
||||
social: any;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "Baner",
|
||||
data: (): BanerData => ({
|
||||
social: [
|
||||
{
|
||||
icon: "mdi-web",
|
||||
link: "https://wulkanowy.github.io",
|
||||
},
|
||||
{
|
||||
icon: "mdi-github",
|
||||
link: "https://github.com/wulkanowy",
|
||||
},
|
||||
{
|
||||
icon: "mdi-twitter",
|
||||
link: "https://twitter.com/wulkanowy",
|
||||
},
|
||||
{
|
||||
icon: "mdi-facebook",
|
||||
link: "https://facebook.com/wulkanowy",
|
||||
},
|
||||
{
|
||||
icon: "mdi-discord",
|
||||
link: "https://discord.gg/vccAQBr",
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
</script>
|
|
@ -1,12 +0,0 @@
|
|||
<template>
|
||||
<div id="loading" class="d-flex fill-height justify-center align-center">
|
||||
<v-progress-circular indeterminate color="primary" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
export default Vue.extend({
|
||||
name: "Loading",
|
||||
});
|
||||
</script>
|
|
@ -1,144 +0,0 @@
|
|||
<template>
|
||||
<div id="login-form" class="fill-height">
|
||||
<v-form @submit.prevent="login" class="d-flex fill-height flex-column">
|
||||
<v-card-title class="d-flex justify-center text-center"
|
||||
>Sign in with the student or parent account</v-card-title
|
||||
>
|
||||
<div class="px-5">
|
||||
<v-text-field outlined label="Email" v-model="loginData.username" :rules="[rules.required]" />
|
||||
<v-text-field
|
||||
outlined
|
||||
label="Password"
|
||||
v-model="loginData.password"
|
||||
:rules="[rules.required]"
|
||||
:type="showPassword ? 'text' : 'password'"
|
||||
:append-icon="showPassword ? 'mdi-eye' : 'mdi-eye-off'"
|
||||
@click:append="showPassword = !showPassword"
|
||||
/>
|
||||
<v-autocomplete
|
||||
outlined
|
||||
label="Symbol"
|
||||
v-model="loginData.symbol"
|
||||
:rules="[rules.required]"
|
||||
:items="
|
||||
loginData.selectedRegisterVariantName == 'Fakelog'
|
||||
? ['powiatwulkanowy', 'adsf']
|
||||
: symbols
|
||||
"
|
||||
/>
|
||||
<v-select
|
||||
outlined
|
||||
label="UONET+ register variant"
|
||||
v-model="loginData.selectedRegisterVariantName"
|
||||
:rules="[rules.required]"
|
||||
:items="registerVariantsNames"
|
||||
@change="registerVariantSelected()"
|
||||
/>
|
||||
</div>
|
||||
<v-card-actions class="px-5 pb-5 pt-0 mt-auto">
|
||||
<v-spacer />
|
||||
<v-btn color="primary" type="submit">Sign in</v-btn>
|
||||
</v-card-actions>
|
||||
</v-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import Api from "@/api";
|
||||
import RegisterVariants from "@/assets/res/registers.json";
|
||||
import Symbols from "@/assets/res/symbols.json";
|
||||
|
||||
interface LoginFormData {
|
||||
loginData: {
|
||||
username: string;
|
||||
password: string;
|
||||
symbol: string;
|
||||
selectedRegisterVariantName: string;
|
||||
};
|
||||
registerVariantsNames: Array<string>;
|
||||
symbols: Array<string>;
|
||||
showPassword: boolean;
|
||||
rules: any;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
data: (): LoginFormData => ({
|
||||
loginData: {
|
||||
username: "",
|
||||
password: "",
|
||||
symbol: "",
|
||||
selectedRegisterVariantName: "Vulcan",
|
||||
},
|
||||
registerVariantsNames: [],
|
||||
symbols: [],
|
||||
showPassword: false,
|
||||
rules: {
|
||||
required: (value: string) => !!value || "This field are required.",
|
||||
},
|
||||
}),
|
||||
|
||||
created() {
|
||||
this.registerVariantsNames = RegisterVariants.map((item): string => item.name);
|
||||
this.symbols = Symbols;
|
||||
},
|
||||
|
||||
computed: {
|
||||
host() {
|
||||
return RegisterVariants[
|
||||
RegisterVariants.findIndex(
|
||||
(item) => item.name === this.loginData.selectedRegisterVariantName
|
||||
)
|
||||
].host;
|
||||
},
|
||||
ssl() {
|
||||
return RegisterVariants[
|
||||
RegisterVariants.findIndex(
|
||||
(item) => item.name === this.loginData.selectedRegisterVariantName
|
||||
)
|
||||
].ssl;
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
registerVariantSelected() {
|
||||
if (this.loginData.selectedRegisterVariantName == "Fakelog") {
|
||||
this.loginData.username = "jan@fakelog.cf";
|
||||
this.loginData.password = "jan123";
|
||||
this.loginData.symbol = "powiatwulkanowy";
|
||||
}
|
||||
},
|
||||
async login() {
|
||||
const state = this.$store.state;
|
||||
state.loading = true;
|
||||
state.error.show = false;
|
||||
state.error.description = "";
|
||||
state.logged_in = false;
|
||||
state.selected_student = undefined;
|
||||
|
||||
if (!this.loginData.username || !this.loginData.password || !this.loginData.symbol) {
|
||||
state.error.description = "All fields are required!";
|
||||
state.error.show = true;
|
||||
state.loading = false;
|
||||
} else {
|
||||
let response: any = await Api.login(
|
||||
this.loginData.username,
|
||||
this.loginData.password,
|
||||
this.loginData.symbol,
|
||||
this.host,
|
||||
this.ssl
|
||||
);
|
||||
if (response) {
|
||||
this.$store.state.loginData = response.data;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.theme--dark.v-btn {
|
||||
color: #1e1e1e !important;
|
||||
}
|
||||
</style>
|
|
@ -1,66 +1,54 @@
|
|||
<template>
|
||||
<div id="select-student" class="fill-height">
|
||||
<v-form @submit.prevent="select_student" class="fill-height d-flex flex-column">
|
||||
<v-card-title class="d-flex justify-center">Select Student</v-card-title>
|
||||
<div id="login-students-list" class="overflow-y-auto">
|
||||
<v-list>
|
||||
<v-list-item-group color="primary" v-model="$store.state.selected_student" mandatory>
|
||||
<v-list-item
|
||||
v-for="(student, id) in this.$store.state.loginData.students"
|
||||
:key="id"
|
||||
:value="id"
|
||||
>
|
||||
<template #default="{ active }">
|
||||
<v-list-item-action>
|
||||
<v-icon
|
||||
:color="active ? 'primary' : ''"
|
||||
v-text="active ? 'mdi-radiobox-marked' : 'mdi-radiobox-blank'"
|
||||
/>
|
||||
</v-list-item-action>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>
|
||||
{{ student.student_name }}
|
||||
{{ student.student_second_name }}
|
||||
{{ student.student_surname }}
|
||||
{{ student.level }}{{ student.symbol }}
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle>{{ student.school_name }}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
</div>
|
||||
<v-card-actions class="px-5 pb-5 pt-0 mt-auto">
|
||||
<v-spacer />
|
||||
<v-btn color="primary" type="submit">Sign in</v-btn>
|
||||
</v-card-actions>
|
||||
</v-form>
|
||||
</div>
|
||||
<v-row align="center">
|
||||
<v-col cols="12">
|
||||
<a>Select student to login!</a>
|
||||
</v-col>
|
||||
<v-col cols="12">
|
||||
<v-radio-group v-model="radioGroup" @change="$store.state.selectedStudent = radioGroup">
|
||||
<v-radio
|
||||
v-model="selectedStudent"
|
||||
v-for="student in this.$store.state.loginData.data.students.data"
|
||||
:key="student.UczenPelnaNazwa"
|
||||
:label="student.UczenPelnaNazwa">
|
||||
</v-radio>
|
||||
</v-radio-group>
|
||||
</v-col>
|
||||
<v-col cols="12">
|
||||
<v-btn
|
||||
class="login-button"
|
||||
depressed
|
||||
color="primary"
|
||||
@click="chooseClicked()">
|
||||
Choose</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
export default Vue.extend({
|
||||
name: "SelectStudent",
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SelectStudent',
|
||||
data() {
|
||||
return {
|
||||
radioGroup: 0,
|
||||
selectedStudent: '',
|
||||
studentList: {
|
||||
type: Array,
|
||||
},
|
||||
};
|
||||
},
|
||||
beforeMount() {
|
||||
console.log(this.$store.state.loginData.data.students.data[0]);
|
||||
},
|
||||
methods: {
|
||||
select_student() {
|
||||
this.$router.push("/user");
|
||||
async chooseClicked() {
|
||||
this.$store.state.selectedUser = this.selectedStudent;
|
||||
this.$store.state.showStudentsList = true;
|
||||
await this.$router.push('/user');
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@media only screen and (min-width: 960px) {
|
||||
#login-students-list {
|
||||
max-height: 410px;
|
||||
}
|
||||
}
|
||||
<style scoped>
|
||||
|
||||
.theme--dark.v-btn {
|
||||
color: #1e1e1e !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
<template>
|
||||
<div id="snackbar">
|
||||
<v-snackbar v-model="$store.state.error.show">
|
||||
{{ this.$store.state.error.description }}
|
||||
<template #action="{ attrs }">
|
||||
<v-dialog width="650" v-if="$store.state.error.details">
|
||||
<template #activator="{ on }">
|
||||
<v-btn color="snackbar" text v-on="on">Details</v-btn>
|
||||
</template>
|
||||
<template #default="dialog">
|
||||
<v-card>
|
||||
<v-card-title>Details</v-card-title>
|
||||
<v-card-text>
|
||||
<v-alert text type="error">
|
||||
{{ $store.state.error.description }}
|
||||
<code class="d-block mt-3 py-2 px-sm-3">
|
||||
{{ $store.state.error.details }}
|
||||
</code>
|
||||
</v-alert>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn text color="primary" @click="dialog.value = false">Close</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</template>
|
||||
</v-dialog>
|
||||
<v-btn color="snackbar" text v-bind="attrs" @click="$store.state.error.show = false"
|
||||
>Close</v-btn
|
||||
>
|
||||
</template>
|
||||
</v-snackbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
export default Vue.extend({
|
||||
name: "Snackbar",
|
||||
});
|
||||
</script>
|
93
frontend/src/components/Login/UserLogin.vue
Normal file
|
@ -0,0 +1,93 @@
|
|||
<template>
|
||||
<div>
|
||||
<v-row align="center">
|
||||
<v-col cols="12"></v-col>
|
||||
<v-col cols="12">
|
||||
<v-text-field
|
||||
class="login-input"
|
||||
v-model="login"
|
||||
label="E-mail"
|
||||
outlined
|
||||
clearable>
|
||||
</v-text-field>
|
||||
<v-text-field
|
||||
class="login-input"
|
||||
v-model="password"
|
||||
label="Password"
|
||||
outlined
|
||||
clearable>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12">
|
||||
<v-select
|
||||
:items="diaryNames"
|
||||
v-model="selectedDiary"
|
||||
item-value=""
|
||||
v-on:change="itemSelected()"
|
||||
label="Symbol"
|
||||
selection="index"
|
||||
outlined></v-select>
|
||||
</v-col>
|
||||
<v-col cols="12">
|
||||
<v-btn
|
||||
class="login-button"
|
||||
depressed
|
||||
color="primary"
|
||||
@click="loginUser()">
|
||||
Log in!</v-btn>
|
||||
<v-divider style="padding: 5px"></v-divider>
|
||||
<a style="">You forgot password click here!</a>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import login from '../../api/login';
|
||||
import diary from '../../assets/data/diary.json';
|
||||
|
||||
interface Login {
|
||||
login: string
|
||||
password: string
|
||||
diaryNames: Array<string>
|
||||
selectedDiary: string
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'UserLogin',
|
||||
data: (): Login => ({
|
||||
login: '',
|
||||
password: '',
|
||||
diaryNames: [],
|
||||
selectedDiary: '',
|
||||
}),
|
||||
created() {
|
||||
this.diaryNames = diary.diaries.map((item): string => item.name);
|
||||
},
|
||||
methods: {
|
||||
async loginUser() {
|
||||
Vue.set(this.$store.state, 'isLoading', true);
|
||||
const index = diary.diaries.findIndex((item) => item.name === this.selectedDiary);
|
||||
const response = await login.login(this.login, this.password,
|
||||
'powiatwulkanowy', diary.diaries[index].url);
|
||||
this.$store.state.loginData = response.data;
|
||||
|
||||
if (this.$store.state.loginData.data.students.data.length > 1) {
|
||||
this.$store.state.isLoading = false;
|
||||
this.$store.state.showStudentsList = true;
|
||||
}
|
||||
},
|
||||
itemSelected() {
|
||||
if (this.selectedDiary === 'Fakelog') {
|
||||
this.login = 'jan@fakelog.tk';
|
||||
this.password = 'jan123';
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -1,68 +0,0 @@
|
|||
<template>
|
||||
<div id="account-manager">
|
||||
<v-dialog width="450" scrollable>
|
||||
<template #activator="{ on }">
|
||||
<v-btn icon v-on="on">
|
||||
<v-avatar color="primary" class="white--text">{{ initials }}</v-avatar>
|
||||
</v-btn>
|
||||
</template>
|
||||
<template #default="dialog">
|
||||
<v-card>
|
||||
<v-card-title>Select student</v-card-title>
|
||||
<v-divider></v-divider>
|
||||
<div class="overflow-y-auto">
|
||||
<v-list>
|
||||
<v-list-item-group color="primary" v-model="$store.state.selected_student" mandatory>
|
||||
<v-list-item v-for="(student, id) in students" :key="id" :value="id">
|
||||
<template #default="{ active }">
|
||||
<v-list-item-action>
|
||||
<v-icon
|
||||
:color="active ? 'primary' : ''"
|
||||
v-text="active ? 'mdi-radiobox-marked' : 'mdi-radiobox-blank'"
|
||||
/>
|
||||
</v-list-item-action>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>
|
||||
{{ student.student_name }}
|
||||
{{ student.student_second_name }}
|
||||
{{ student.student_surname }}
|
||||
{{ student.level }}{{ student.symbol }}
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle>{{ student.school_name }}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
</div>
|
||||
<v-divider></v-divider>
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn text color="primary" @click="$store.commit('log_out')">Log out</v-btn>
|
||||
<v-btn text color="primary" @click="dialog.value = false">Close</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</template>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
export default Vue.extend({
|
||||
name: "AccountManager",
|
||||
computed: {
|
||||
students() {
|
||||
return this.$store.state.loginData.students;
|
||||
},
|
||||
initials() {
|
||||
const index = this.$store.state.selected_student;
|
||||
return (
|
||||
this.$store.state.loginData.students[index].student_name.charAt(0) +
|
||||
this.$store.state.loginData.students[index].student_surname.charAt(0)
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -1,26 +0,0 @@
|
|||
<template>
|
||||
<div id="app-bar">
|
||||
<v-app-bar app clipped-left>
|
||||
<v-btn icon @click="$store.commit('drawer_show')">
|
||||
<v-icon>mdi-menu</v-icon>
|
||||
</v-btn>
|
||||
<v-btn icon @click="$store.commit('drawer_mini')" v-if="!$store.state.small_ui">
|
||||
<v-icon v-if="$store.state.drawer.mini">mdi-chevron-right</v-icon>
|
||||
<v-icon v-else>mdi-chevron-left</v-icon>
|
||||
</v-btn>
|
||||
<v-toolbar-title>{{ this.$store.state.view }}</v-toolbar-title>
|
||||
<v-spacer />
|
||||
<AccountManager />
|
||||
</v-app-bar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import AccountManager from "../../components/Panel/AccountManager.vue";
|
||||
|
||||
export default Vue.extend({
|
||||
name: "AppBar",
|
||||
components: { AccountManager },
|
||||
});
|
||||
</script>
|
75
frontend/src/components/Panel/Appbar.vue
Normal file
|
@ -0,0 +1,75 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<v-app-bar
|
||||
app
|
||||
color="primary"
|
||||
dark>
|
||||
<v-app-bar-nav-icon
|
||||
@click="changeDrawerState">
|
||||
</v-app-bar-nav-icon>
|
||||
<v-toolbar-title>Wulkanowy - {{ this.$store.state.appbarTitle }}</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-menu offset-y class="text-center" style="width: 200px">
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-avatar
|
||||
v-on="on"
|
||||
color="blue">
|
||||
<span class="white--text headline">{{ initials }}</span>
|
||||
</v-avatar>
|
||||
</template>
|
||||
<v-list>
|
||||
<v-list-item @click="changeStudent" link>
|
||||
<v-icon>mdi-account-arrow-right</v-icon>
|
||||
<v-list-item-title>Change Student</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-divider></v-divider>
|
||||
<v-list-item @click="logout" link>
|
||||
<v-icon>mdi-logout</v-icon>
|
||||
<v-list-item-title>Logout</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-app-bar>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import router from '../../router';
|
||||
|
||||
export default {
|
||||
name: 'Appbar',
|
||||
data: () => ({
|
||||
name: 'Dashboard',
|
||||
onAvatarClicked: false,
|
||||
initials: 'TK',
|
||||
}),
|
||||
beforeMount() {
|
||||
this.initials = this.getInitials();
|
||||
},
|
||||
methods: {
|
||||
changeDrawerState() {
|
||||
this.$store.state.drawer = !this.$store.state.drawer;
|
||||
},
|
||||
async logout() {
|
||||
document.cookie = '';
|
||||
this.$store.state.showStudentsList = false;
|
||||
this.$store.state.loginData = null;
|
||||
await router.push('/');
|
||||
},
|
||||
async changeStudent() {
|
||||
await router.push('/');
|
||||
},
|
||||
getInitials() {
|
||||
const index = this.$store.state.selectedStudent;
|
||||
return this.$store.state.loginData.data.students.data[index].UczenImie.charAt(0)
|
||||
+ this.$store.state.loginData.data.students.data[index].UczenNazwisko.charAt(0);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -1,20 +1,88 @@
|
|||
<template>
|
||||
<div id="drawer">
|
||||
<div>
|
||||
<v-navigation-drawer
|
||||
:mini-variant="$store.state.drawer.mini && !$store.state.small_ui"
|
||||
v-model="$store.state.drawer.show"
|
||||
clipped
|
||||
app
|
||||
>
|
||||
<v-list nav dense>
|
||||
<v-list-item-group v-model="$store.state.view" mandatory color="primary">
|
||||
<v-list-item v-for="(item, i) in nav" :key="i" :value="item.name">
|
||||
v-model="this.$store.state.drawer"
|
||||
:mini-variant.sync="mini"
|
||||
pernament>
|
||||
<v-list>
|
||||
<v-list-item class="px-2">
|
||||
<v-list-item-avatar>
|
||||
<v-icon>mdi-account</v-icon>
|
||||
</v-list-item-avatar>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="title">
|
||||
{{ nameSurname }}
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle>{{ className }}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
<v-btn
|
||||
icon
|
||||
@click.stop="mini = !mini">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</v-btn>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<v-divider></v-divider>
|
||||
<v-list
|
||||
nav
|
||||
dense>
|
||||
<v-list-item-group
|
||||
v-model="this.$store.state.group">
|
||||
<v-list-item>
|
||||
<v-list-item-icon>
|
||||
<v-icon>{{ item.icon }}</v-icon>
|
||||
<v-icon>mdi-home</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="text-capitalize">{{ item.name }}</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
<v-list-item-title>Dashboard</v-list-item-title>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item>
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-numeric-6-box-multiple-outline</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-title>Grades</v-list-item-title>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item>
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-table</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-title>Attendance</v-list-item-title>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item>
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-table-clock</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-title>Timetable</v-list-item-title>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item>
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-email-outline</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-title>Messages</v-list-item-title>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item>
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-notebook-outline</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-title>Homework</v-list-item-title>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item>
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-devices</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-title>Mobile Devices</v-list-item-title>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item>
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-domain</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-title>School</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
|
@ -22,79 +90,34 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
interface DrawerData {
|
||||
nav: any;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "Drawer",
|
||||
|
||||
data: (): DrawerData => ({
|
||||
nav: [
|
||||
{
|
||||
icon: "mdi-view-dashboard-outline",
|
||||
name: "dashboard",
|
||||
},
|
||||
{
|
||||
icon: "mdi-numeric-6-box-multiple-outline",
|
||||
name: "grades",
|
||||
},
|
||||
{
|
||||
icon: "mdi-table-edit",
|
||||
name: "attedance",
|
||||
},
|
||||
{
|
||||
icon: "mdi-timetable",
|
||||
name: "timetable",
|
||||
},
|
||||
{
|
||||
icon: "mdi-calendar",
|
||||
name: "exams",
|
||||
},
|
||||
{
|
||||
icon: "mdi-notebook-outline",
|
||||
name: "homework",
|
||||
},
|
||||
{
|
||||
icon: "mdi-trophy-outline",
|
||||
name: "notes and achievements",
|
||||
},
|
||||
{
|
||||
icon: "mdi-clover",
|
||||
name: "lucky number",
|
||||
},
|
||||
{
|
||||
icon: "mdi-account-multiple-outline",
|
||||
name: "conferences",
|
||||
},
|
||||
{
|
||||
icon: "mdi-alert-circle-outline",
|
||||
name: "school annocuments",
|
||||
},
|
||||
{
|
||||
icon: "mdi-domain",
|
||||
name: "school and teachers",
|
||||
},
|
||||
{
|
||||
icon: "mdi-card-account-details-outline",
|
||||
name: "student data",
|
||||
},
|
||||
{
|
||||
icon: "mdi-devices",
|
||||
name: "mobile devices",
|
||||
},
|
||||
{
|
||||
icon: "mdi-email-outline",
|
||||
name: "messages",
|
||||
},
|
||||
{
|
||||
icon: "mdi-cog-outline",
|
||||
name: "settings",
|
||||
},
|
||||
],
|
||||
<script>
|
||||
export default {
|
||||
name: 'Drawer',
|
||||
data: () => ({
|
||||
mini: false,
|
||||
nameSurname: '',
|
||||
className: '',
|
||||
}),
|
||||
});
|
||||
beforeMount() {
|
||||
const index = this.$store.state.selectedStudent;
|
||||
this.nameSurname = `${this.getName(index)} ${this.getSurname(index)}`;
|
||||
this.className = this.getClassName(index);
|
||||
},
|
||||
methods: {
|
||||
getName(index) {
|
||||
return this.$store.state.loginData.data.students.data[index].UczenImie;
|
||||
},
|
||||
getSurname(index) {
|
||||
return this.$store.state.loginData.data.students.data[index].UczenNazwisko;
|
||||
},
|
||||
getClassName(index) {
|
||||
return this.$store.state.loginData.data.students.data[index].Poziom.toString()
|
||||
+ this.$store.state.loginData.data.students.data[index].Symbol;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
// Login
|
||||
export { default as LoginForm } from "./Login/LoginForm.vue";
|
||||
export { default as SelectStudent } from "./Login/SelectStudent.vue";
|
||||
export { default as Loading } from "./Login/Loading.vue";
|
||||
export { default as Baner } from "./Login/Baner.vue";
|
||||
export { default as Snackbar } from "./Login/Snackbar.vue";
|
||||
|
||||
// Panel
|
||||
export { default as AppBar } from "./Panel/AppBar.vue";
|
||||
export { default as Drawer } from "./Panel/Drawer.vue";
|
||||
export { default as AccountManager } from "./Panel/AccountManager.vue";
|
|
@ -1,8 +1,9 @@
|
|||
import Vue from "vue";
|
||||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
import store from "./store";
|
||||
import vuetify from "./plugins/vuetify";
|
||||
import Vue from 'vue';
|
||||
import App from './App.vue';
|
||||
import './registerServiceWorker';
|
||||
import router from './router';
|
||||
import store from './store';
|
||||
import vuetify from './plugins/vuetify';
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
|
@ -11,4 +12,4 @@ new Vue({
|
|||
store,
|
||||
vuetify,
|
||||
render: (h) => h(App),
|
||||
}).$mount("#app");
|
||||
}).$mount('#app');
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import Vue from "vue";
|
||||
import Vuetify from "vuetify/lib";
|
||||
import Vue from 'vue';
|
||||
import Vuetify from 'vuetify/lib/framework';
|
||||
import colors from 'vuetify/lib/util/colors';
|
||||
|
||||
Vue.use(Vuetify);
|
||||
|
||||
|
@ -7,14 +8,9 @@ export default new Vuetify({
|
|||
theme: {
|
||||
themes: {
|
||||
light: {
|
||||
primary: "#9a0007",
|
||||
error: "#ff5722",
|
||||
snackbar: "#e57373",
|
||||
},
|
||||
dark: {
|
||||
primary: "#e57373",
|
||||
error: "#ff5722",
|
||||
snackbar: "#9a0007",
|
||||
primary: colors.red.darken1, // #E53935
|
||||
secondary: colors.red.lighten4, // #FFCDD2
|
||||
accent: colors.indigo.base, // #3F51B5
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
32
frontend/src/registerServiceWorker.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* eslint-disable no-console */
|
||||
|
||||
import { register } from 'register-service-worker';
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
register(`${process.env.BASE_URL}service-worker.js`, {
|
||||
ready() {
|
||||
console.log(
|
||||
'App is being served from cache by a service worker.\n'
|
||||
+ 'For more details, visit https://goo.gl/AFskqB',
|
||||
);
|
||||
},
|
||||
registered() {
|
||||
console.log('Service worker has been registered.');
|
||||
},
|
||||
cached() {
|
||||
console.log('Content has been cached for offline use.');
|
||||
},
|
||||
updatefound() {
|
||||
console.log('New content is downloading.');
|
||||
},
|
||||
updated() {
|
||||
console.log('New content is available; please refresh.');
|
||||
},
|
||||
offline() {
|
||||
console.log('No internet connection found. App is running in offline mode.');
|
||||
},
|
||||
error(error) {
|
||||
console.error('Error during service worker registration:', error);
|
||||
},
|
||||
});
|
||||
}
|
|
@ -1,30 +1,31 @@
|
|||
import Vue from "vue";
|
||||
import VueRouter, { RouteConfig } from "vue-router";
|
||||
import Login from "@/views/Login.vue";
|
||||
import Panel from "@/views/Panel.vue";
|
||||
import Vue from 'vue';
|
||||
import VueRouter, { RouteConfig } from 'vue-router';
|
||||
import Login from '../views/Login.vue';
|
||||
|
||||
Vue.use(VueRouter);
|
||||
|
||||
const routes: Array<RouteConfig> = [
|
||||
{
|
||||
path: "/",
|
||||
name: "Login",
|
||||
path: '/',
|
||||
name: 'Login',
|
||||
component: Login,
|
||||
},
|
||||
{
|
||||
path: "/user",
|
||||
name: "User",
|
||||
component: Panel,
|
||||
path: '/about',
|
||||
name: 'About',
|
||||
// route level code-splitting
|
||||
// this generates a separate chunk (about.[hash].js) for this route
|
||||
// which is lazy-loaded when the route is visited.
|
||||
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'),
|
||||
},
|
||||
{
|
||||
path: "*",
|
||||
redirect: "/",
|
||||
path: '/user',
|
||||
name: 'User',
|
||||
component: () => import('../views/Panel.vue'),
|
||||
},
|
||||
];
|
||||
|
||||
const router = new VueRouter({
|
||||
mode: "history",
|
||||
base: process.env.BASE_URL,
|
||||
routes,
|
||||
});
|
||||
|
||||
|
|
4
frontend/src/shims-tsx.d.ts
vendored
|
@ -1,4 +1,4 @@
|
|||
import Vue, { VNode } from "vue";
|
||||
import Vue, { VNode } from 'vue';
|
||||
|
||||
declare global {
|
||||
namespace JSX {
|
||||
|
@ -7,7 +7,7 @@ declare global {
|
|||
// tslint:disable no-empty-interface
|
||||
interface ElementClass extends Vue {}
|
||||
interface IntrinsicElements {
|
||||
[elem: string]: any;
|
||||
[elem: string]: any
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
5
frontend/src/shims-vue.d.ts
vendored
|
@ -1,4 +1,5 @@
|
|||
declare module "*.vue" {
|
||||
import Vue from "vue";
|
||||
declare module '*.vue' {
|
||||
import Vue from 'vue';
|
||||
|
||||
export default Vue;
|
||||
}
|
||||
|
|
5
frontend/src/shims-vuetify.d.ts
vendored
|
@ -1,4 +1,5 @@
|
|||
declare module "vuetify/lib/framework" {
|
||||
import Vuetify from "vuetify";
|
||||
declare module 'vuetify/lib/framework' {
|
||||
import Vuetify from 'vuetify';
|
||||
|
||||
export default Vuetify;
|
||||
}
|
||||
|
|
|
@ -1,58 +1,28 @@
|
|||
import Vue from "vue";
|
||||
import Vuex from "vuex";
|
||||
import router from "@/router";
|
||||
import Vue from 'vue';
|
||||
import Vuex, { Store } from 'vuex';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
interface State {
|
||||
loading: boolean;
|
||||
loginData: any;
|
||||
logged_in: boolean;
|
||||
selected_student: number;
|
||||
small_ui: boolean;
|
||||
view: string;
|
||||
drawer: {
|
||||
show: boolean;
|
||||
mini: boolean;
|
||||
};
|
||||
error: {
|
||||
show: boolean;
|
||||
description: string;
|
||||
details: string;
|
||||
};
|
||||
interface IndexState {
|
||||
drawer: boolean
|
||||
group: any
|
||||
mini: boolean
|
||||
appbarTitle: string
|
||||
selectedStudent: number
|
||||
}
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: (): State => ({
|
||||
loading: false,
|
||||
loginData: [],
|
||||
logged_in: false,
|
||||
selected_student: 0,
|
||||
small_ui: false,
|
||||
view: "dashboard",
|
||||
drawer: {
|
||||
show: true,
|
||||
mini: false,
|
||||
},
|
||||
error: {
|
||||
show: false,
|
||||
description: "",
|
||||
details: "",
|
||||
},
|
||||
state: (): IndexState => ({
|
||||
drawer: true,
|
||||
group: null,
|
||||
mini: true,
|
||||
appbarTitle: 'Dashboard',
|
||||
selectedStudent: 0,
|
||||
}),
|
||||
mutations: {
|
||||
log_out(state) {
|
||||
state.loginData = [];
|
||||
state.logged_in = false;
|
||||
router.push("/")
|
||||
},
|
||||
drawer_show(state) {
|
||||
state.drawer.show = !state.drawer.show
|
||||
},
|
||||
drawer_mini(state) {
|
||||
state.drawer.mini = !state.drawer.mini
|
||||
},
|
||||
},
|
||||
actions: {},
|
||||
modules: {},
|
||||
actions: {
|
||||
},
|
||||
modules: {
|
||||
},
|
||||
});
|
||||
|
|
24
frontend/src/store/login.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
interface LoginState {
|
||||
isLoading: boolean
|
||||
loginData: any
|
||||
showStudentsList: boolean
|
||||
}
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: (): LoginState => ({
|
||||
isLoading: false,
|
||||
loginData: null,
|
||||
showStudentsList: false,
|
||||
}),
|
||||
mutations: {
|
||||
},
|
||||
actions: {
|
||||
},
|
||||
modules: {
|
||||
},
|
||||
});
|
5
frontend/src/views/About.vue
Normal file
|
@ -0,0 +1,5 @@
|
|||
<template>
|
||||
<div class="about">
|
||||
<h1>This is an about page</h1>
|
||||
</div>
|
||||
</template>
|
|
@ -1,71 +1,66 @@
|
|||
<template>
|
||||
<div id="login" class="d-flex fill-hieght justify-center align-center">
|
||||
<v-card id="login-card" elevation="15">
|
||||
<v-row no-gutters class="d-flex fill-height">
|
||||
<v-col cols="12" md="5" class="primary rounded-l d-md-flex d-none">
|
||||
<Baner />
|
||||
</v-col>
|
||||
<v-col cols="12" md="7">
|
||||
<LoginForm v-if="!this.$store.state.logged_in & !this.$store.state.loading" />
|
||||
<Loading v-if="this.$store.state.loading" />
|
||||
<SelectStudent v-if="this.$store.state.logged_in & !this.$store.state.loading" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card>
|
||||
<Snackbar />
|
||||
<div id="login">
|
||||
<img class="image" src="../assets/logo_login.svg" width="500" alt="Wulkanowy">
|
||||
<v-main style="width: 100%;">
|
||||
<v-card
|
||||
:loading="this.$store.state.isLoading"
|
||||
elevation="24"
|
||||
id="login-form"
|
||||
class="mx-auto mt-9">
|
||||
<form>
|
||||
<v-container>
|
||||
<UserLogin v-if="!this.$store.state.showStudentsList"></UserLogin>
|
||||
<SelectStudent v-if="this.$store.state.showStudentsList"></SelectStudent>
|
||||
</v-container>
|
||||
</form>
|
||||
</v-card>
|
||||
</v-main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import { LoginForm, SelectStudent, Loading, Baner, Snackbar } from "@/components";
|
||||
|
||||
export default Vue.extend({
|
||||
name: "Login",
|
||||
<script>
|
||||
import UserLogin from '../components/Login/UserLogin.vue';
|
||||
import SelectStudent from '../components/Login/SelectStudent.vue';
|
||||
|
||||
export default {
|
||||
name: 'Login',
|
||||
components: {
|
||||
LoginForm,
|
||||
Loading,
|
||||
SelectStudent,
|
||||
Baner,
|
||||
Snackbar,
|
||||
UserLogin,
|
||||
},
|
||||
beforeMount() {
|
||||
if (this.$store.state.logged_in) {
|
||||
this.$router.push("/user");
|
||||
}
|
||||
methods: {
|
||||
getLoading() {
|
||||
return this.$store.state.isLoading;
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
<style>
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#login {
|
||||
background: linear-gradient(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1)),
|
||||
url("../assets/img/login_wallpaper.jpg");
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
background-image: url("../assets/wallpaper.jpg");
|
||||
background-size: cover;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 959px) {
|
||||
#login-card {
|
||||
width: 100vw;
|
||||
min-height: 100vh;
|
||||
border-radius: 0;
|
||||
|
||||
.row {
|
||||
min-height: 100vh;
|
||||
}
|
||||
}
|
||||
#login-form {
|
||||
width: 500px;
|
||||
top: 15%;
|
||||
bottom: 50%;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 960px) {
|
||||
#login-card {
|
||||
width: 750px;
|
||||
.login-input {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.row {
|
||||
align-items: stretch;
|
||||
}
|
||||
}
|
||||
.login-button {
|
||||
margin: 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,59 +1,25 @@
|
|||
<template>
|
||||
<div id="panel">
|
||||
<AppBar />
|
||||
<Drawer />
|
||||
<v-main>
|
||||
<v-container fluid>
|
||||
<v-window v-model="$store.state.view" touchless>
|
||||
<v-window-item transition="false" value="dashboard">this is dashbaord</v-window-item>
|
||||
<v-window-item transition="false" value="grades">this is grades</v-window-item>
|
||||
<v-window-item transition="false" value="attedance">this is attedance</v-window-item>
|
||||
<v-window-item transition="false" value="timetable">this is timetable</v-window-item>
|
||||
<v-window-item transition="false" value="exams">this is exams</v-window-item>
|
||||
<v-window-item transition="false" value="homework">this is homework</v-window-item>
|
||||
<v-window-item transition="false" value="notes and achievements"
|
||||
>this is notes</v-window-item
|
||||
>
|
||||
<v-window-item transition="false" value="lucky number"
|
||||
>this is lucky number</v-window-item
|
||||
>
|
||||
<v-window-item transition="false" value="conferences">this is conferences</v-window-item>
|
||||
<v-window-item transition="false" value="school annocuments"
|
||||
>this is school annocuments</v-window-item
|
||||
>
|
||||
<v-window-item transition="false" value="student data"
|
||||
>this is student data</v-window-item
|
||||
>
|
||||
<v-window-item transition="false" value="school and teachers"
|
||||
>this is school and teachers</v-window-item
|
||||
>
|
||||
<v-window-item transition="false" value="mobile devices"
|
||||
>this is mobile devices</v-window-item
|
||||
>
|
||||
<v-window-item transition="false" value="messages">this is messages</v-window-item>
|
||||
<v-window-item transition="false" value="settings">this is settings</v-window-item>
|
||||
</v-window>
|
||||
</v-container>
|
||||
</v-main>
|
||||
<div>
|
||||
<div id="appbar">
|
||||
<Appbar></Appbar>
|
||||
<Drawer></Drawer>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import { AppBar, Drawer } from "@/components";
|
||||
|
||||
export default Vue.extend({
|
||||
name: "Panel",
|
||||
<script>
|
||||
import Appbar from '../components/Panel/Appbar.vue';
|
||||
import Drawer from '../components/Panel/Drawer.vue';
|
||||
|
||||
export default {
|
||||
name: 'Panel',
|
||||
components: {
|
||||
AppBar,
|
||||
Appbar,
|
||||
Drawer,
|
||||
},
|
||||
|
||||
beforeMount() {
|
||||
if (!this.$store.state.logged_in) {
|
||||
this.$router.push("/");
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
|
88
frontend/static/frontend/css/start.css
Normal file
|
@ -0,0 +1,88 @@
|
|||
body {
|
||||
padding: 0 !important;
|
||||
height: 100vh;
|
||||
background: #fff;
|
||||
overflow: auto;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
font-family: 'Poppins', sans-serif;
|
||||
font-size: 14px;
|
||||
margin: 0 !important;
|
||||
color: black;
|
||||
}
|
||||
/*.logo img[data-v-cd2b8d62] {
|
||||
width: 768px;
|
||||
max-width: 30vw;
|
||||
display: inline;
|
||||
-webkit-filter: drop-shadow(0 5px 5px rgba(0,0,0,.2)) drop-shadow(0 8px 10px rgba(0,0,0,.14)) drop-shadow(0 3px 14px rgba(0,0,0,.12));
|
||||
filter: drop-shadow(0 5px 5px rgba(0,0,0,.2)) drop-shadow(0 8px 10px rgba(0,0,0,.14)) drop-shadow(0 3px 14px rgba(0,0,0,.12));
|
||||
}*/
|
||||
|
||||
#container{
|
||||
width: 100%;
|
||||
}
|
||||
#menu{
|
||||
width: 95%;
|
||||
height: 18%;
|
||||
margin-left: 2.5%;
|
||||
border-bottom: 4px solid white;
|
||||
border-radius: 3px;
|
||||
font-family: 'Open Sans Condensed', sans-serif;
|
||||
font-family: 'Quicksand', sans-serif;
|
||||
}
|
||||
.option{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.grade {
|
||||
display: block;
|
||||
border-radius: 5px;
|
||||
cursor: pointer !important;
|
||||
font-size: 20px !important;
|
||||
width: 25px !important;
|
||||
height: 30px !important;
|
||||
text-align: center !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
margin-top: 5px !important;
|
||||
}
|
||||
|
||||
.noteElement {
|
||||
padding: 10px;
|
||||
border: black 1px solid;
|
||||
width: 90%;
|
||||
height: 75px;
|
||||
margin-top: 5px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.noteContent {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.achievementElement {
|
||||
padding: 10px;
|
||||
border: black 1px solid;
|
||||
width: 90%;
|
||||
height: 75px;
|
||||
margin-top: 5px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.log-out {
|
||||
float: right;
|
||||
margin-right: 10px;
|
||||
color: blue;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#bar {
|
||||
background-color: #d32f2f;
|
||||
}
|
||||
|
||||
.MuiTouchRipple-rippleVisible {
|
||||
color: #d32f2f !important;
|
||||
opacity: 100% !important;
|
||||
}
|
126
frontend/static/frontend/css/style.css
Normal file
|
@ -0,0 +1,126 @@
|
|||
@media screen and (max-width: 768px) {
|
||||
#box-content {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
width: 0 !important;
|
||||
position: relative !important;
|
||||
top: 30% !important;
|
||||
}
|
||||
|
||||
#box {
|
||||
left: 27% !important;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 0 !important;
|
||||
}
|
||||
|
||||
#icons {
|
||||
width: 0% !important;
|
||||
}
|
||||
}
|
||||
body {
|
||||
height: 100vh;
|
||||
background: -webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,.3)),to(rgba(0,0,0,.3))),url(../images/wallpaper.b24bba72.jpg);
|
||||
background: linear-gradient(rgba(0,0,0,.3),rgba(0,0,0,.3)),url(../images/wallpaper.jpg);
|
||||
background-size: cover;
|
||||
background-position: 50%;
|
||||
background-attachment: fixed;
|
||||
overflow: auto;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 10px;
|
||||
margin: 0 !important;
|
||||
color: black;
|
||||
}
|
||||
|
||||
#box {
|
||||
background-color: white;
|
||||
padding: 5em;
|
||||
width: 30vw;
|
||||
position: absolute;
|
||||
top: 35%;
|
||||
left: 32%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#box-content {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#form {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.logo img[data-v-cd2b8d62] {
|
||||
width: 768px;
|
||||
-webkit-filter: drop-shadow(0 5px 5px rgba(0,0,0,.2)) drop-shadow(0 8px 10px rgba(0,0,0,.14)) drop-shadow(0 3px 14px rgba(0,0,0,.12));
|
||||
filter: drop-shadow(0 5px 5px rgba(0,0,0,.2)) drop-shadow(0 8px 10px rgba(0,0,0,.14)) drop-shadow(0 3px 14px rgba(0,0,0,.12));
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
img {
|
||||
font-size: 70%;
|
||||
margin-bottom: 70%;
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: inline-block;
|
||||
width: 50px;
|
||||
margin: 0px;
|
||||
margin-left: 0.6%;
|
||||
margin-right: 0.6%;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
#icons {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 80%;
|
||||
margin-bottom: 8em;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
a {
|
||||
font-size: 120%;
|
||||
color: blue;
|
||||
margin-bottom: 5%;
|
||||
}
|
||||
|
||||
#help-box {
|
||||
font-size: 200%;
|
||||
}
|
||||
|
||||
p {
|
||||
size: 0px;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
height: 48px;
|
||||
margin-bottom: 15px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#button {
|
||||
background-color: #d32f2f;
|
||||
border-radius: 0;
|
||||
margin-top: 10%;
|
||||
}
|
||||
|
||||
#error {
|
||||
color: red;
|
||||
}
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
BIN
frontend/static/frontend/images/book-outline.png
Normal file
After Width: | Height: | Size: 432 B |
39
frontend/static/frontend/images/discord.e9241a54.svg
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="200"
|
||||
width="200"
|
||||
version="1.1"
|
||||
viewBox="0 0 200 200"
|
||||
id="Layer_1">
|
||||
<metadata
|
||||
id="metadata13">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs11" />
|
||||
<style
|
||||
id="style2">.st0{fill:#FFFFFF;}</style>
|
||||
<path
|
||||
style="fill:#ffffff"
|
||||
id="path4"
|
||||
d="m 81.9,83.9 c -5.7,0 -10.2,5 -10.2,11.1 0,6.1 4.6,11.1 10.2,11.1 5.7,0 10.2,-5 10.2,-11.1 0.1,-6.1 -4.5,-11.1 -10.2,-11.1 z m 36.5,0 c -5.7,0 -10.2,5 -10.2,11.1 0,6.1 4.6,11.1 10.2,11.1 5.7,0 10.2,-5 10.2,-11.1 0,-6.1 -4.5,-11.1 -10.2,-11.1 z"
|
||||
class="st0" />
|
||||
<path
|
||||
style="fill:#ffffff"
|
||||
id="path6"
|
||||
d="M 167,0 H 33 C 21.7,0 12.5,9.2 12.5,20.6 v 135.2 c 0,11.4 9.2,20.6 20.5,20.6 h 113.4 l -5.3,-18.5 12.8,11.9 12.1,11.2 21.5,19 V 20.6 C 187.5,9.2 178.3,0 167,0 Z m -38.6,130.6 c 0,0 -3.6,-4.3 -6.6,-8.1 13.1,-3.7 18.1,-11.9 18.1,-11.9 -4.1,2.7 -8,4.6 -11.5,5.9 -5,2.1 -9.8,3.5 -14.5,4.3 -9.6,1.8 -18.4,1.3 -25.9,-0.1 -5.7,-1.1 -10.6,-2.7 -14.7,-4.3 -2.3,-0.9 -4.8,-2 -7.3,-3.4 -0.3,-0.2 -0.6,-0.3 -0.9,-0.5 -0.2,-0.1 -0.3,-0.2 -0.4,-0.3 -1.8,-1 -2.8,-1.7 -2.8,-1.7 0,0 4.8,8 17.5,11.8 -3,3.8 -6.7,8.3 -6.7,8.3 C 50.6,129.9 42.2,115.4 42.2,115.4 42.2,83.2 56.6,57.1 56.6,57.1 71,46.3 84.7,46.6 84.7,46.6 l 1,1.2 c -18,5.2 -26.3,13.1 -26.3,13.1 0,0 2.2,-1.2 5.9,-2.9 10.7,-4.7 19.2,-6 22.7,-6.3 0.6,-0.1 1.1,-0.2 1.7,-0.2 6.1,-0.8 13,-1 20.2,-0.2 9.5,1.1 19.7,3.9 30.1,9.6 0,0 -7.9,-7.5 -24.9,-12.7 l 1.4,-1.6 c 0,0 13.7,-0.3 28.1,10.5 0,0 14.4,26.1 14.4,58.3 0,0 -8.5,14.5 -30.6,15.2 z"
|
||||
class="st0" />
|
||||
</svg>
|
After Width: | Height: | Size: 2 KiB |
31
frontend/static/frontend/images/email.ce588d18.svg
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="svg4"
|
||||
viewBox="0 0 22 22"
|
||||
height="22"
|
||||
width="22"
|
||||
version="1.1">
|
||||
<metadata
|
||||
id="metadata10">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs8" />
|
||||
<path
|
||||
style="fill:#ffffff"
|
||||
id="path2"
|
||||
d="M 19,7 11,12 3,7 V 5 l 8,5 8,-5 M 19,3 H 3 C 1.89,3 1,3.89 1,5 v 12 a 2,2 0 0 0 2,2 h 16 a 2,2 0 0 0 2,-2 V 5 C 21,3.89 20.1,3 19,3 Z" />
|
||||
</svg>
|
After Width: | Height: | Size: 896 B |