Skip to content

Feature/cursor #307

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 38 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
8bbca9c
feature: add cursor settings
subscorp Feb 16, 2021
056adc5
fix: fixed conflicts
subscorp Feb 16, 2021
914a808
fix: fixed pytest issue
subscorp Feb 16, 2021
05660da
fix: fixed conflicts
subscorp Feb 16, 2021
8312440
update: changed CursorSettings table to UserSettings
subscorp Feb 17, 2021
0db4d2b
fix:solved conflicts
subscorp Feb 17, 2021
53de34a
fix: fixed a small bug
subscorp Feb 17, 2021
6dd0219
fix: another small fix
subscorp Feb 17, 2021
fc72d95
fix: fixed issues according to comments
subscorp Feb 18, 2021
25ca2d3
fix: fixed conflicts
subscorp Feb 18, 2021
4d2195e
Update: now using the new login system
subscorp Feb 21, 2021
2114a33
fix: fixed conflicts
subscorp Feb 21, 2021
4ce2c74
fix: fixed issues according to comments
subscorp Feb 21, 2021
4f06799
fix: fixed issues according to comments
subscorp Feb 23, 2021
f569f3c
fix: fixed conflicts
subscorp Feb 23, 2021
e289578
Update: moved functions to internals
subscorp Feb 23, 2021
44da8b7
fix: fixed issue in pytest
subscorp Feb 23, 2021
7b616ec
Merge branch 'develop' of https://github.com/PythonFreeCourse/calenda…
subscorp Feb 23, 2021
8b0cd21
fix: a small fix
subscorp Feb 23, 2021
dbae35d
fix: fixed issues according to comments
subscorp Feb 25, 2021
03e21d1
fix: fixed conflicts
subscorp Feb 25, 2021
458fb3f
fix: fixed a bug in pytest
subscorp Feb 25, 2021
df699f6
fix: fixed a small bug in one of the tests. now coverage is 100% on t…
subscorp Feb 25, 2021
c847b41
fix: fixed issues according to comments
subscorp Feb 25, 2021
479f580
fix: fixed conflicts
subscorp Feb 25, 2021
b01c459
fix: a tiny fix
subscorp Feb 25, 2021
969bcb1
fix: fixed finale comment
subscorp Feb 26, 2021
d0336bf
Merge branch 'develop' of https://github.com/PythonFreeCourse/calenda…
subscorp Feb 26, 2021
01456c8
fix: trying to fix the same bug from favorite_quotes in pytest
subscorp Feb 26, 2021
5b54d04
fix: fixed issue in pytest
subscorp Feb 26, 2021
0fdce31
fix: trying to fix the bug
subscorp Feb 26, 2021
7dcfc02
fix: trying to fix the bug
subscorp Feb 26, 2021
021881b
fix: trying to fix the bug
subscorp Feb 26, 2021
8e057c5
fix: trying to fix the bug
subscorp Feb 26, 2021
2ec4a77
fix: trying to fix the bug
subscorp Feb 26, 2021
d050246
fix: trying to fix the bug
subscorp Feb 26, 2021
a1a9f66
fix: fixed the bug!
subscorp Feb 26, 2021
6d2bcf5
fix: fixed conflicts
subscorp Feb 26, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions app/database/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,20 @@ def __repr__(self):
)


class UserSettings(Base):
__tablename__ = "user_settings"

id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("users.id"))
music_on = Column(Boolean, default=False, nullable=False)
music_vol = Column(Integer, default=None)
sfx_on = Column(Boolean, default=False, nullable=False)
sfx_vol = Column(Integer, default=None)
primary_cursor = Column(String, default="default", nullable=False)
secondary_cursor = Column(String, default="default", nullable=False)
video_game_releases = Column(Boolean, default=False)


class Joke(Base):
__tablename__ = "jokes"

Expand Down
1 change: 1 addition & 0 deletions app/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
MEDIA_PATH = os.path.join(APP_PATH, config.MEDIA_DIRECTORY)
STATIC_PATH = os.path.join(APP_PATH, "static")
TEMPLATES_PATH = os.path.join(APP_PATH, "templates")
CURSORS_PATH = os.path.join(APP_PATH, "media/cursors/")

templates = Jinja2Templates(directory=TEMPLATES_PATH)
templates.env.add_extension('jinja2.ext.i18n')
Expand Down
49 changes: 38 additions & 11 deletions app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from app import config
from app.database import engine, models
from app.dependencies import get_db, logger, MEDIA_PATH, STATIC_PATH, templates
from app.dependencies import MEDIA_PATH, STATIC_PATH, get_db, logger, templates
from app.internal import daily_quotes, json_data_loader
from app.internal.languages import set_ui_language
from app.internal.security.ouath2 import auth_exception_handler
Expand All @@ -17,11 +17,11 @@


def create_tables(engine, psql_environment):
if 'sqlite' in str(engine.url) and psql_environment:
if "sqlite" in str(engine.url) and psql_environment:
raise models.PSQLEnvironmentError(
"You're trying to use PSQL features on SQLite env.\n"
"Please set app.config.PSQL_ENVIRONMENT to False "
"and run the app again."
"and run the app again.",
)
else:
models.Base.metadata.create_all(bind=engine)
Expand All @@ -40,10 +40,33 @@ def create_tables(engine, psql_environment):
set_ui_language()

from app.routers import ( # noqa: E402
about_us, agenda, calendar, categories, celebrity, credits,
currency, dayview, email, event, export, four_o_four, friendview,
google_connect, invitation, joke, login, logout, profile,
register, search, telegram, user, weekview, weight, whatsapp,
about_us,
agenda,
calendar,
categories,
celebrity,
credits,
currency,
cursor,
dayview,
email,
event,
export,
four_o_four,
friendview,
google_connect,
invitation,
joke,
login,
logout,
profile,
register,
search,
telegram,
user,
weekview,
weight,
whatsapp,
)

json_data_loader.load_to_database(next(get_db()))
Expand Down Expand Up @@ -73,6 +96,7 @@ async def swagger_ui_redirect():
celebrity.router,
credits.router,
currency.router,
cursor.router,
dayview.router,
email.router,
event.router,
Expand Down Expand Up @@ -105,10 +129,13 @@ async def swagger_ui_redirect():
@logger.catch()
async def home(request: Request, db: Session = Depends(get_db)):
quote = daily_quotes.get_quote_of_day(db)
return templates.TemplateResponse("index.html", {
"request": request,
"quote": quote,
})
return templates.TemplateResponse(
"index.html",
{
"request": request,
"quote": quote,
},
)


custom_openapi(app)
Binary file added app/media/cursors/Material_3d.cur
Binary file not shown.
Binary file added app/media/cursors/Minecraft.cur
Binary file not shown.
Binary file added app/media/cursors/Valentine_Heart.cur
Binary file not shown.
Binary file added app/media/cursors/Wand.cur
Binary file not shown.
Binary file added app/media/cursors/alternate_select.cur
Binary file not shown.
Binary file added app/media/cursors/arrow.cur
Binary file not shown.
Binary file added app/media/cursors/blue_cursor.cur
Binary file not shown.
Binary file added app/media/cursors/blue_finger.cur
Binary file not shown.
Binary file added app/media/cursors/cloud.cur
Binary file not shown.
11 changes: 11 additions & 0 deletions app/media/cursors/credits.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
http://www.rw-designer.com/cursor-set/material-amber
http://www.rw-designer.com/cursor-set/windows-xp-style
http://www.rw-designer.com/cursor-set/material-3d
http://www.rw-designer.com/cursor-set/cloudflix
http://www.rw-designer.com/cursor-set/primogem
http://www.rw-designer.com/cursor-set/paper-plane
http://www.rw-designer.com/cursor-set/yodalighsaber
http://www.rw-designer.com/cursor-set/valentine-heart
http://www.rw-designer.com/cursor-set/icy-ice
http://www.rw-designer.com/cursor-set/wii-hand-1
http://www.rw-designer.com/cursor-set/minecraft-sets
Binary file added app/media/cursors/finger.cur
Binary file not shown.
Binary file added app/media/cursors/green_cursor.cur
Binary file not shown.
Binary file added app/media/cursors/green_finger.cur
Binary file not shown.
Binary file added app/media/cursors/green_lightsaber.cur
Binary file not shown.
Binary file added app/media/cursors/ice.cur
Binary file not shown.
Binary file added app/media/cursors/lime_cursor.cur
Binary file not shown.
Binary file added app/media/cursors/p1.cur
Binary file not shown.
Binary file added app/media/cursors/pink_cursor.cur
Binary file not shown.
Binary file added app/media/cursors/pointer.cur
Binary file not shown.
Binary file added app/media/cursors/red_cursor.cur
Binary file not shown.
Binary file added app/media/cursors/red_finger.cur
Binary file not shown.
Binary file added app/media/cursors/xp_arrow.cur
Binary file not shown.
Binary file added app/media/cursors/xp_pencil.cur
Binary file not shown.
Binary file added app/media/cursors/yellow_cursor.cur
Binary file not shown.
Binary file added app/media/cursors/yellow_finger.cur
Binary file not shown.
153 changes: 153 additions & 0 deletions app/routers/cursor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import json
from pathlib import Path
from typing import List, Optional, Tuple

from app.database.models import User, UserSettings
from app.dependencies import CURSORS_PATH, get_db, templates
from fastapi import APIRouter, Depends, Form, Request
from sqlalchemy.orm.session import Session
from starlette.responses import RedirectResponse
from starlette.status import HTTP_302_FOUND
from app.internal.security.dependancies import current_user

router = APIRouter(
prefix="/cursor",
tags=["cursor"],
Comment on lines +14 to +16
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we need a route for every setting option. This should probably be routers.setting.py and the calls should be:

  • @router.get("/settings/cursor")
  • @router.post("/settings/cursor")
  • @router.get("/{user_id}/cursor")

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean that there shouldn't be a [setting_type].py file for each setting type?
So if I have Audio Settings and Cursor Settings, both of them should be in routers.setting.py, but the @router functions should stay the same, only in this new file instead of the old one?
Thanks for your feedback!

responses={404: {"description": "Not found"}},
)


@router.get("/settings")
def cursor_settings(
request: Request,
user: User = Depends(current_user),
session: Session = Depends(get_db),
) -> templates.TemplateResponse:
"""A route to the cursor settings.

Args:
request (Request): the http request.
session (Session): the database.

Returns:
templates.TemplateResponse: renders the cursor_settings.html page
with the relevant information.
"""
cursors = ["default"] + [
path.stem for path in Path(CURSORS_PATH).glob("**/*.cur")
]

return templates.TemplateResponse(
"cursor_settings.html",
{
"request": request,
"cursors": cursors,
},
)


@router.post("/settings")
async def get_cursor_choices(
session: Session = Depends(get_db),
user: User = Depends(current_user),
primary_cursor: str = Form(...),
secondary_cursor: str = Form(...),
) -> RedirectResponse:
"""The form in which the user choses primary and secondary
cursors.

Args:
session (Session, optional): the database.
user (User, optional): [description]. temp user.
primary_cursor (str, optional): name of the primary cursor.
the primary cursor.
secondary_cursor (str, optional): name of the secondary cursor.

Returns:
RedirectResponse: redirects to the homepage.
"""
cursor_choices = {
"primary_cursor": primary_cursor,
"secondary_cursor": secondary_cursor,
}
save_cursor_settings(session, user, cursor_choices)

return RedirectResponse("/", status_code=HTTP_302_FOUND)


@router.get("/load_cursor")
async def load_cursor(
session: Session = Depends(get_db),
user: User = Depends(current_user),
) -> RedirectResponse:
"""loads cursors according to cursor settings.

Args:
session (Session): the database.
user (User): the user.

Returns:
RedirectResponse: redirect the user to the homepage.
"""
primary_cursor, secondary_cursor = get_cursor_settings(
session,
user.user_id,
)

return json.dumps(
{
"primary_cursor": primary_cursor,
"secondary_cursor": secondary_cursor,
},
)


def get_cursor_settings(
session: Session,
user_id: int,
) -> Tuple[Optional[List[str]], Optional[int], Optional[str], Optional[int]]:
"""Retrieves cursor settings from the database.

Args:
session (Session): the database.
user_id (int, optional): the users' id.

Returns:
Tuple[str, Optional[List[str]], Optional[int],
str, Optional[str], Optional[int]]: the cursor settings.
"""
primary_cursor, secondary_cursor = None, None
cursor_settings = (
session.query(UserSettings).filter_by(user_id=user_id).first()
)
if cursor_settings:
primary_cursor = cursor_settings.primary_cursor
secondary_cursor = cursor_settings.secondary_cursor

return primary_cursor, secondary_cursor


def save_cursor_settings(
session: Session,
user: User,
cursor_choices: List[str],
):
"""Saves cursor choices in the db.

Args:
session (Session): the database.
user (User): current user.
cursor_choices (List[str]): primary and secondary cursors.
"""
cursor_settings = (
session.query(UserSettings).filter_by(user_id=user.user_id).first()
)
if cursor_settings:
session.query(UserSettings).filter_by(
user_id=cursor_settings.user_id,
).update(cursor_choices)
session.commit()
else:
cursor_settings = UserSettings(user_id=user.user_id, **cursor_choices)
session.add(cursor_settings)
session.commit()
39 changes: 39 additions & 0 deletions app/static/cursor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
CURSORS_PATH = "/media/cursors/";
window.addEventListener("load", get_cursor_choices);

/**
* @summary This function gets cursor choices from the db.
*/
function get_cursor_choices() {
let request = new XMLHttpRequest();
request.open("GET", "/cursor/load_cursor", true);
request.onload = change_cursor;
request.send();
}

/**
* @summary This function changes the primary cursor and the secondary
* cursor according to users' choices.
*/
function change_cursor() {
let cursor_settings = JSON.parse(JSON.parse(this.response));
let primary_cursor = cursor_settings["primary_cursor"];
let primary_cursor_val = `url(${CURSORS_PATH}${primary_cursor}), auto`;
let secondary_cursor = cursor_settings["secondary_cursor"];
let secondary_cursor_val = `url(${CURSORS_PATH}${secondary_cursor}), auto`;
if (primary_cursor != "default.cur") {
primary_val = primary_cursor_val;
} else {
primary_val = "";
}
document.body.style.cursor = primary_val;
let links = document.querySelectorAll("a, button, input, select, label");
if (secondary_cursor != "default.cur") {
secondary_val = secondary_cursor_val;
} else {
secondary_val = "";
}
links.forEach((element) => {
element.style.cursor = secondary_val;
});
}
9 changes: 8 additions & 1 deletion app/static/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ p {
border: none;
background-color: whitesmoke;
}

.error-message {
line-height: 0;
color: red;
Expand Down Expand Up @@ -125,3 +125,10 @@ p {
h2.modal-title {
font-size: 1.25rem;
}

#primary-cursor,
#secondary-cursor {
width: 10em;
height: 2.5em;
margin-top: 0.5em;
}
7 changes: 6 additions & 1 deletion app/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@
<li class="nav-item">
<a class="nav-link" href="{{ url_for('agenda') }}">Agenda</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('cursor_settings') }}">Cursor Settings</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('view_invitations') }}">Invitations</a>
</li>
Expand Down Expand Up @@ -81,6 +84,8 @@
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js" integrity="sha512-d9xgZrVZpmmQlfonhQUvTR7lMPtO7NkZMkA0ABN3PHCbKA5nqylQ/yWlFAyY6hYgdF1Qh6nYiuADWwKB4C2WSw==" crossorigin="anonymous"></script>
<script type="text/javascript" src="{{ url_for('static', path='/popover.js') }}"></script>
<script defer type="text/javascript" src="{{ url_for('static', path='/cursor.js') }}"></script>

<!-- This bootstrap version is needed here because of the toggler bug in the beta version-->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha2/js/bootstrap.bundle.min.js" integrity="sha384-BOsAfwzjNJHrJ8cZidOg56tcQWfp6y72vEJ8xQ9w6Quywb24iOsW913URv1IS4GD" crossorigin="anonymous"></script>
<script src="{{ url_for('static', path='/horoscope.js') }}"></script>
Expand All @@ -89,4 +94,4 @@

</body>

</html>
</html>
27 changes: 27 additions & 0 deletions app/templates/cursor_settings.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{% extends "base.html" %}
{% block content %}
<div class="container mt-4">
<h1>Cursor Settings</h1>
<form action="{{ url_for('get_cursor_choices') }}" method="post" id="cursor-form">
<label for="primary-cusor">Select primary cursor :</label> <br>
<select name="primary_cursor" id="primary-cursor" class="form-control">
{% for cursor in cursors %}
<option value="{{ cursor }}.cur">{{cursor}}</option>
{% endfor %}
</select>
<br>
<label for="secondary-cusor">Select secondary cursor :</label> <br>
<select name="secondary_cursor" id="secondary-cursor" class="form-control">
{% for cursor in cursors %}
<option value="{{ cursor }}.cur">{{cursor}}</option>
{% endfor %}
</select>
<br>
<button id="activate-cursor" type="submit" form="cursor-form" class="btn btn-primary">
Activate
</button>
<br>
</form>
</div>

{% endblock %}
Loading