Browse Source

Add account-default theme setting

merge-requests/34/head
Celeo 6 years ago
committed by Chad Birch
parent
commit
9fbfab2c96
  1. 24
      tildes/alembic/versions/347859b0355e_added_account_default_theme_setting.py
  2. 18
      tildes/scss/modules/_form.scss
  3. 16
      tildes/static/js/behaviors/theme-selector.js
  4. 10
      tildes/tests/conftest.py
  5. 7
      tildes/tests/webtests/test_user_settings.py
  6. 1
      tildes/tildes/models/user/user.py
  7. 2
      tildes/tildes/templates/base.jinja2
  8. 2
      tildes/tildes/templates/base_no_sidebar.jinja2
  9. 27
      tildes/tildes/templates/settings.jinja2
  10. 16
      tildes/tildes/views/api/web/user.py
  11. 11
      tildes/tildes/views/settings.py

24
tildes/alembic/versions/347859b0355e_added_account_default_theme_setting.py

@ -0,0 +1,24 @@
"""Added account default theme setting
Revision ID: 347859b0355e
Revises: 3fbddcba0e3b
Create Date: 2018-08-11 16:23:13.297883
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "347859b0355e"
down_revision = "3fbddcba0e3b"
branch_labels = None
depends_on = None
def upgrade():
op.add_column("users", sa.Column("theme_default", sa.Text()))
def downgrade():
op.drop_column("users", "theme_default")

18
tildes/scss/modules/_form.scss

@ -38,6 +38,10 @@ select.form-select:not([multiple]) {
} }
} }
.form-buttons.no-reverse {
flex-direction: row;
}
textarea.form-input { textarea.form-input {
height: 8rem; height: 8rem;
line-height: 1.5; line-height: 1.5;
@ -74,6 +78,20 @@ textarea.form-input {
} }
} }
.form-oneline {
display: flex;
font-size: 0.6rem;
margin-bottom: 0.4rem;
.form-oneline-item {
flex: 2;
}
.form-oneline-item-double {
flex: 4;
}
}
.form-search .form-input { .form-search .form-input {
margin-right: 0.4rem; margin-right: 0.4rem;
} }

16
tildes/static/js/behaviors/theme-selector.js

@ -2,7 +2,13 @@ $.onmount('[data-js-theme-selector]', function() {
$(this).change(function(event) { $(this).change(function(event) {
event.preventDefault(); event.preventDefault();
// hide any IC change message
$(this).parent().find('.form-status').hide();
var new_theme = $(this).val(); var new_theme = $(this).val();
var selected_text = $(this).find('option:selected').text();
var $setDefaultLink = $('#button-set-default-theme');
var $formDefaultValue = $('#input-set-default-theme');
// persist the new theme for the user in their cookie // persist the new theme for the user in their cookie
document.cookie = 'theme=' + new_theme + ';' + document.cookie = 'theme=' + new_theme + ';' +
@ -22,5 +28,15 @@ $.onmount('[data-js-theme-selector]', function() {
if (new_theme) { if (new_theme) {
$body.addClass('theme-' + new_theme); $body.addClass('theme-' + new_theme);
} }
// set the IC hidden input with the new value
$formDefaultValue.val(new_theme);
// set visibility of 'Set as account default' link
if (selected_text.indexOf('(account default)') !== -1) {
$setDefaultLink.css('visibility', 'hidden');
} else {
$setDefaultLink.css('visibility', 'visible');
}
}); });
}); });

10
tildes/tests/conftest.py

@ -199,7 +199,15 @@ def webtest(base_app):
# create the TestApp - note that specifying wsgi.url_scheme is necessary so that the # create the TestApp - note that specifying wsgi.url_scheme is necessary so that the
# secure cookies from the session library will work # secure cookies from the session library will work
app = TestApp( app = TestApp(
base_app, extra_environ={"wsgi.url_scheme": "https"}, cookiejar=CookieJar()
base_app,
# This "tm.active" is a temporary fix around this fixture failing to rollback
# data after the tests are complete (it effectively deactivates pyramid_tm).
extra_environ={
"wsgi.url_scheme": "https",
"tm.active": True,
"REMOTE_ADDR": "0.0.0.0",
},
cookiejar=CookieJar(),
) )
# fetch the login page, fill in the form, and submit it (sets the cookie) # fetch the login page, fill in the form, and submit it (sets the cookie)

7
tildes/tests/webtests/test_user_settings.py

@ -0,0 +1,7 @@
def test_render_theme_options(webtest):
"""Test that theme settings are being rendered."""
settings = webtest.get("/settings")
assert settings.status_int == 200
assert settings.text.count("(site and account default)") == 1
assert "(site default)" not in settings.text
assert "(account default)" not in settings.text

1
tildes/tildes/models/user/user.py

@ -87,6 +87,7 @@ class User(DatabaseModel):
Boolean, nullable=False, server_default="false" Boolean, nullable=False, server_default="false"
) )
open_new_tab_text: bool = Column(Boolean, nullable=False, server_default="false") open_new_tab_text: bool = Column(Boolean, nullable=False, server_default="false")
theme_default: str = Column(Text)
is_banned: bool = Column(Boolean, nullable=False, server_default="false") is_banned: bool = Column(Boolean, nullable=False, server_default="false")
permissions: Any = Column(JSONB) permissions: Any = Column(JSONB)
home_default_order: Optional[TopicSortOption] = Column(ENUM(TopicSortOption)) home_default_order: Optional[TopicSortOption] = Column(ENUM(TopicSortOption))

2
tildes/tildes/templates/base.jinja2

@ -38,6 +38,8 @@
{% block body_tag %} {% block body_tag %}
{% if request.cookies.get('theme', '') %} {% if request.cookies.get('theme', '') %}
<body class="theme-{{ request.cookies.get('theme', '') }}"> <body class="theme-{{ request.cookies.get('theme', '') }}">
{% elif request.user and request.user.theme_default %}
<body class="theme-{{ request.user.theme_default }}">
{% else %} {% else %}
<body> <body>
{% endif %} {% endif %}

2
tildes/tildes/templates/base_no_sidebar.jinja2

@ -3,6 +3,8 @@
{% block body_tag %} {% block body_tag %}
{% if request.cookies.get('theme', '') %} {% if request.cookies.get('theme', '') %}
<body class="l-no-sidebar theme-{{ request.cookies.get('theme', '') }}"> <body class="l-no-sidebar theme-{{ request.cookies.get('theme', '') }}">
{% elif request.user and request.user.theme_default %}
<body class="l-no-sidebar theme-{{ request.user.theme_default }}">
{% else %} {% else %}
<body class="l-no-sidebar"> <body class="l-no-sidebar">
{% endif %} {% endif %}

27
tildes/tildes/templates/settings.jinja2

@ -8,14 +8,37 @@
<ul class="settings-list"> <ul class="settings-list">
<li> <li>
<label for="theme">Choose a display theme:</label> <label for="theme">Choose a display theme:</label>
<select class="form-select" name="theme" id="theme" data-js-theme-selector>
<div class="form-oneline">
<select class="form-select form-oneline-item-double" name="theme" id="theme" data-js-theme-selector>
{% for theme, description in theme_options.items() %} {% for theme, description in theme_options.items() %}
<option <option
value="{{ theme }}" value="{{ theme }}"
{{ 'selected' if theme == current_theme else '' }} {{ 'selected' if theme == current_theme else '' }}
>{{ description }}</option>
>
{{ description }}
</option>
{% endfor %} {% endfor %}
</select> </select>
<div class="form-oneline-item">
<form
name="account-default-theme"
data-ic-patch-to="{{ request.route_url(
'ic_user',
username=request.user.username
) }}"
>
<input type="hidden" name="theme" id="input-set-default-theme" value="{{ current_theme }}">
<div class="form-buttons no-reverse">
<button id="button-set-default-theme"
class="btn btn-link
{% if current_theme == request.user.theme_default %}d-invisible{% endif %}"
>
Set as account default
</button>
</div>
</form>
</div>
</div>
</li> </li>
<li> <li>
<form <form

16
tildes/tildes/views/api/web/user.py

@ -196,6 +196,22 @@ def patch_change_track_comment_visits(request: Request) -> Response:
return Response("Disabled tracking of last comment visit.") return Response("Disabled tracking of last comment visit.")
@ic_view_config(
route_name="user",
request_method="PATCH",
request_param="ic-trigger-name=account-default-theme",
permission="change_account_default_theme_setting",
)
def patch_change_account_default_theme(request: Request) -> Response:
"""Change the user's "theme account default" setting."""
user = request.context
new_theme = request.params.get("theme")
user.theme_default = new_theme
return IC_NOOP
@ic_view_config( @ic_view_config(
route_name="user_invite_code", route_name="user_invite_code",
request_method="GET", request_method="GET",

11
tildes/tildes/views/settings.py

@ -14,18 +14,25 @@ from tildes.schemas.user import EMAIL_ADDRESS_NOTE_MAX_LENGTH, UserSchema
PASSWORD_FIELD = UserSchema(only=("password",)).fields["password"] PASSWORD_FIELD = UserSchema(only=("password",)).fields["password"]
DEFAULT_THEME_NAME = "white"
@view_config(route_name="settings", renderer="settings.jinja2") @view_config(route_name="settings", renderer="settings.jinja2")
def get_settings(request: Request) -> dict: def get_settings(request: Request) -> dict:
"""Generate the user settings page.""" """Generate the user settings page."""
current_theme = request.cookies.get("theme", "")
current_theme = request.cookies.get("theme", "") or request.user.theme_default
user_default = request.user.theme_default or DEFAULT_THEME_NAME
theme_options = { theme_options = {
"": "White (default)",
"white": "White",
"light": "Solarized Light", "light": "Solarized Light",
"dark": "Solarized Dark", "dark": "Solarized Dark",
"black": "Black", "black": "Black",
} }
if DEFAULT_THEME_NAME == user_default:
theme_options[DEFAULT_THEME_NAME] += " (site and account default)"
else:
theme_options[user_default] += " (account default)"
theme_options[DEFAULT_THEME_NAME] += " (site default)"
return {"current_theme": current_theme, "theme_options": theme_options} return {"current_theme": current_theme, "theme_options": theme_options}

Loading…
Cancel
Save