source: OpenWorkouts-current/ow/views/user.py @ 31adfa5

currentfeature/docs
Last change on this file since 31adfa5 was 31adfa5, checked in by borja <borja@…>, 5 years ago

(#14) Timezones support:

  • Added pytz as a new dependency, please install it in your existing envs:

pip install pytz

  • Added a timezone attribute to users, to store in which timezone they are, defaults to 'UTC'. Ensure any users you could have in your database have such attribute. You can add it in pshell:

for user in root.users:

user.timezone = 'UTC'

request.tm.commit()

  • Modified schemas/templates/views to let users choose their timezone based on a list of "common" timezones provided by pytz
  • Added two methods to the Workout model so we can get the start and end dates formatted in the appropiate timezone (all datetime objects are stored in UTC)
  • Modified the templates where we show workout dates and times so the new timezone-formatting methods are used.
  • Property mode set to 100644
File size: 5.7 KB
Line 
1from pyramid.httpexceptions import HTTPFound
2from pyramid.view import view_config
3from pyramid.security import remember, forget
4from pyramid.response import Response
5from pyramid.i18n import TranslationStringFactory
6from pyramid_simpleform import Form, State
7from pytz import common_timezones
8
9from ..models.user import User
10from ..schemas.user import (
11    UserProfileSchema,
12    ChangePasswordSchema,
13    SignUpSchema,
14)
15from ..models.root import OpenWorkouts
16from ..views.renderers import OWFormRenderer
17
18_ = TranslationStringFactory('OpenWorkouts')
19
20
21@view_config(context=OpenWorkouts)
22def dashboard_redirect(context, request):
23    """
24    Send the user to his dashboard when accesing the root object,
25    send to the login page if the user is not logged in.
26    """
27    if request.authenticated_userid:
28        user = request.root.get_user_by_uid(request.authenticated_userid)
29        if user:
30            return HTTPFound(location=request.resource_url(user))
31        else:
32            # an authenticated user session, for an user that does not exist
33            # anymore, logout!
34            return HTTPFound(location=request.resource_url(context, 'logout'))
35    return HTTPFound(location=request.resource_url(context, 'login'))
36
37
38@view_config(
39    context=OpenWorkouts,
40    name='login',
41    renderer='ow:templates/login.pt')
42def login(context, request):
43    message = ''
44    email = ''
45    password = ''
46    return_to = request.params.get('return_to')
47    redirect_url = return_to or request.resource_url(request.root)
48
49    if 'submit' in request.POST:
50        email = request.POST.get('email', None)
51        user = context.get_user_by_email(email)
52        if user:
53            password = request.POST.get('password', None)
54            if password is not None and user.check_password(password):
55                headers = remember(request, str(user.uid))
56                redirect_url = return_to or request.resource_url(user)
57                return HTTPFound(location=redirect_url, headers=headers)
58            else:
59                message = _('Wrong password')
60        else:
61            message = _('Wrong email address')
62
63    return {
64        'message': message,
65        'email': email,
66        'password': password,
67        'redirect_url': redirect_url
68    }
69
70
71@view_config(context=OpenWorkouts, name='logout')
72def logout(context, request):
73    headers = forget(request)
74    return HTTPFound(location=request.resource_url(context), headers=headers)
75
76
77@view_config(
78    context=OpenWorkouts,
79    name='signup',
80    renderer='ow:templates/signup.pt')
81def signup(context, request):
82    state = State(emails=context.lowercase_emails,
83                  names=context.lowercase_nicknames)
84    form = Form(request, schema=SignUpSchema(), state=state)
85
86    if 'submit' in request.POST and form.validate():
87        user = form.bind(User(), exclude=['password_confirm'])
88        context.add_user(user)
89        # Send to login
90        return HTTPFound(location=request.resource_url(context))
91
92    return {
93        'form': OWFormRenderer(form)
94    }
95
96
97@view_config(
98    context=OpenWorkouts,
99    name='forgot-password',
100    renderer='ow:templates/forgot_password.pt')
101def recover_password(context, request):
102    # WIP
103    Form(request)
104
105
106@view_config(
107    context=User,
108    permission='view',
109    renderer='ow:templates/dashboard.pt')
110def dashboard(context, request):
111    """
112    Render a dashboard for the current user
113    """
114    # Add here some logic
115    return {}
116
117
118@view_config(
119    context=User,
120    permission='view',
121    name='profile',
122    renderer='ow:templates/profile.pt')
123def profile(context, request):
124    """
125    "public" profile view, showing some workouts from this user, her
126    basic info, stats, etc
127    """
128    return {}
129
130
131@view_config(
132    context=User,
133    name='picture',
134    permission='view')
135def profile_picture(context, request):
136    return Response(
137        content_type='image',
138        body_file=context.picture.open())
139
140
141@view_config(
142    context=User,
143    permission='edit',
144    name='edit',
145    renderer='ow:templates/edit_profile.pt')
146def edit_profile(context, request):
147    # if not given a file there is an empty byte in POST, which breaks
148    # our blob storage validator.
149    # dirty fix until formencode fixes its api.is_empty method
150    if isinstance(request.POST.get('picture', None), bytes):
151        request.POST['picture'] = ''
152
153    nicknames = request.root.lowercase_nicknames
154    if context.nickname:
155        # remove the current user nickname from the list, preventing form
156        # validation error
157        nicknames.remove(context.nickname.lower())
158    state = State(emails=request.root.lowercase_emails, names=nicknames)
159    form = Form(request, schema=UserProfileSchema(), state=state, obj=context)
160
161    if 'submit' in request.POST and form.validate():
162        # No picture? do not override it
163        if not form.data['picture']:
164            del form.data['picture']
165        form.bind(context)
166        # reindex
167        request.root.reindex(context)
168        # Saved, send the user to the public view of her profile
169        return HTTPFound(location=request.resource_url(context, 'profile'))
170
171    # prevent crashes on the form
172    if 'picture' in form.data:
173        del form.data['picture']
174
175    return {'form': OWFormRenderer(form),
176            'timezones': common_timezones}
177
178
179@view_config(
180    context=User,
181    permission='edit',
182    name='passwd',
183    renderer='ow:templates/change_password.pt')
184def change_password(context, request):
185    form = Form(request, schema=ChangePasswordSchema(),
186                state=State(user=context))
187    if 'submit' in request.POST and form.validate():
188        context.password = form.data['password']
189        return HTTPFound(location=request.resource_url(context, 'profile'))
190    return {'form': OWFormRenderer(form)}
Note: See TracBrowser for help on using the repository browser.