Index: ow/views/bulk.py
===================================================================
--- ow/views/bulk.py	(revision 8c2b0949ae91540ee5c8101b9d5ff39003773da3)
+++ 	(revision )
@@ -1,85 +1,0 @@
-from pyramid.httpexceptions import HTTPFound
-from pyramid.view import view_config
-from pyramid_simpleform import Form
-from pyramid_simpleform.renderers import FormRenderer
-from pyramid.i18n import TranslationStringFactory
-
-from ..models.user import User
-from ..models.bulk import BulkFile
-from ..schemas.bulk import (
-    BulkFileSchema,
-)
-
-_ = TranslationStringFactory('OpenWorkouts')
-
-
-@view_config(
-    context=User,
-    permission='edit',
-    name='add-bulk-file',
-    renderer='ow:templates/add_bulk_file.pt')
-def add_bulk_file(context, request):
-    """
-    Add a compressed file that should contain tracking files, so we can
-    do a "bulk" upload of tracking files and workouts
-    """
-    # if not given a file there is an empty byte in POST, which breaks
-    # our blob storage validator.
-    # dirty fix until formencode fixes its api.is_empty method
-    if isinstance(request.POST.get('compressed_file', None), bytes):
-        request.POST['compressed_file'] = ''
-
-    form = Form(request, schema=BulkFileSchema())
-
-    if 'submit' in request.POST and form.validate():
-        # get the extension of the compressed file. We use this later to
-        # know how to decompress it.
-        file_name = file_ext = request.POST['compressed_file'].filename
-        file_ext = file_name.split('.')[-1]
-        # Create a BulkFile instance based on the input from the form
-        bulk_file = form.bind(BulkFile(uid=str(context.uid)))
-        # Set the type of compressed file
-        bulk_file.file_name = file_name
-        bulk_file.file_type = file_ext
-
-        # save the bulk file
-        request.root['_bulk_files'].add_bulk_file(bulk_file)
-        # Send the user to his/her bulk files page
-        return HTTPFound(location=request.resource_url(context, 'bulk-files'))
-
-    return {
-        'form': FormRenderer(form),
-    }
-
-
-@view_config(
-    context=BulkFile,
-    permission='delete',
-    name='delete',
-    renderer='ow:templates/delete_bulk_file.pt')
-def delete_bulk_file(context, request):
-    """
-    Delete a bulk file
-    """
-    uid = context.uid
-    user = request.root.get_user_by_uid(uid)
-    if 'submit' in request.POST:
-        if request.POST.get('delete', None) == 'yes':
-            del request.root['_bulk_files'][str(context.bfid)]
-            return HTTPFound(location=request.resource_url(user, 'bulk-files'))
-    return {'user': user}
-
-
-@view_config(
-    context=User,
-    permission='edit',
-    name='bulk-files',
-    renderer='ow:templates/bulk_files.pt')
-def bulk_files(context, request):
-    """
-    Render a page where users can see their bulk uploads (finished,
-    pending, status, etc)
-    """
-    return {
-        'bulk_files': request.root['_bulk_files'].get_by_uid(context.uid)
-    }
Index: ow/views/root.py
===================================================================
--- ow/views/root.py	(revision 8c2b0949ae91540ee5c8101b9d5ff39003773da3)
+++ ow/views/root.py	(revision 5ec3a0b5cf5640304a0953320daef2a28bbca9a5)
@@ -1,4 +1,4 @@
 from pyramid.view import view_config
-from pyramid_simpleform import Form, State
+from pyramid_simpleform import Form
 from pyramid_simpleform.renderers import FormRenderer
 from pyramid.httpexceptions import HTTPFound
@@ -18,5 +18,5 @@
     Show a list of all the users to admins
     """
-    users = context.users
+    users = context.users()
     return {'users': users}
 
@@ -31,12 +31,10 @@
     Form to add a user
     """
-    state = State(emails=context.lowercase_emails,
-                  names=context.lowercase_nicknames)
-
-    form = Form(request, schema=UserAddSchema(), state=state)
+    form = Form(request, schema=UserAddSchema())
 
     if 'submit' in request.POST and form.validate():
-        user = form.bind(User())
-        context[str(user.uid)] = user
+        user_id = request.POST['user_id']
+        user = form.bind(User(), exclude=['user_id'])
+        context[user_id] = user
         return HTTPFound(location=request.resource_url(context, 'userlist'))
 
@@ -44,11 +42,2 @@
         'form': FormRenderer(form)
     }
-
-
-@view_config(
-    context=OpenWorkouts,
-    permission='view',
-    name='promo',
-    renderer='ow:templates/openworkouts.pt')
-def promo(context, request):
-    return {}
Index: ow/views/user.py
===================================================================
--- ow/views/user.py	(revision 8c2b0949ae91540ee5c8101b9d5ff39003773da3)
+++ ow/views/user.py	(revision 5ec3a0b5cf5640304a0953320daef2a28bbca9a5)
@@ -1,15 +1,8 @@
-import json
-from datetime import datetime, timezone, timedelta
-from decimal import Decimal
-from io import BytesIO
-
-from pyramid.httpexceptions import HTTPFound, HTTPNotFound
+from pyramid.httpexceptions import HTTPFound
 from pyramid.view import view_config
 from pyramid.security import remember, forget
 from pyramid.response import Response
-from pyramid.i18n import TranslationStringFactory, get_localizer
+from pyramid.i18n import TranslationStringFactory
 from pyramid_simpleform import Form, State
-from pytz import common_timezones
-from PIL import Image
 
 from ..models.user import User
@@ -21,17 +14,6 @@
 from ..models.root import OpenWorkouts
 from ..views.renderers import OWFormRenderer
-from ..utilities import (
-    timedelta_to_hms,
-    get_verification_token,
-    get_gender_names,
-    get_available_locale_names,
-    get_month_names,
-    get_week_day_names
-)
-from ..mail import send_verification_email
 
 _ = TranslationStringFactory('OpenWorkouts')
-month_name = get_month_names()
-weekday_name = get_week_day_names()
 
 
@@ -43,11 +25,6 @@
     """
     if request.authenticated_userid:
-        user = request.root.get_user_by_uid(request.authenticated_userid)
-        if user:
-            return HTTPFound(location=request.resource_url(user))
-        else:
-            # an authenticated user session, for an user that does not exist
-            # anymore, logout!
-            return HTTPFound(location=request.resource_url(context, 'logout'))
+        user = request.root.get_user(request.authenticated_userid)
+        return HTTPFound(location=request.resource_url(user))
     return HTTPFound(location=request.resource_url(context, 'login'))
 
@@ -58,59 +35,28 @@
     renderer='ow:templates/login.pt')
 def login(context, request):
-    # messages is a dict of pre-defined messages we would need to show to the
-    # user when coming back to the login page after certain actions
-    messages = {
-        'already-verified': _('User has been verified already'),
-        'link-sent': _('Verification link sent, please check your inbox'),
-        'max-tokens-sent': _(
-            'We already sent you the verification link more than three times')
-    }
-    message = request.GET.get('message', '')
-    if message:
-        message = messages.get(message, '')
-    email = request.GET.get('email', '')
+    message = ''
+    username = ''
     password = ''
     return_to = request.params.get('return_to')
     redirect_url = return_to or request.resource_url(request.root)
-    # If the user still has to verify the account, this will be set to the
-    # proper link to re-send the verification email
-    resend_verify_link = None
 
     if 'submit' in request.POST:
-        email = request.POST.get('email', None)
-        user = context.get_user_by_email(email)
-        if user:
-            if user.verified:
-                password = request.POST.get('password', None)
-                if password is not None and user.check_password(password):
-                    # look for the value of locale for this user, to set the
-                    # LOCALE cookie, so the UI appears on the pre-selected lang
-                    default_locale = request.registry.settings.get(
-                        'pyramid.default_locale_name')
-                    locale = getattr(user, 'locale', default_locale)
-                    request.response.set_cookie('_LOCALE_', locale)
-                    # log in the user and send back to the place he wanted to
-                    # visit
-                    headers = remember(request, str(user.uid))
-                    request.response.headers.extend(headers)
-                    redirect_url = return_to or request.resource_url(user)
-                    return HTTPFound(location=redirect_url,
-                                     headers=request.response.headers)
-                else:
-                    message = _('Wrong password')
+        username = request.POST.get('username', None)
+        if username in request.root.all_usernames():
+            user = request.root[username]
+            password = request.POST.get('password', None)
+            if password is not None and user.check_password(password):
+                headers = remember(request, username)
+                return HTTPFound(location=redirect_url, headers=headers)
             else:
-                message = _('You have to verify your account first')
-                resend_verify_link = request.resource_url(
-                    user, 'resend-verification-link'
-                )
+                message = u'Bad password'
         else:
-            message = _('Wrong email address')
+            message = u'Bad username'
 
     return {
         'message': message,
-        'email': email,
+        'username': username,
         'password': password,
-        'redirect_url': redirect_url,
-        'resend_verify_link': resend_verify_link
+        'redirect_url': redirect_url
     }
 
@@ -118,9 +64,6 @@
 @view_config(context=OpenWorkouts, name='logout')
 def logout(context, request):
-    request.response.delete_cookie('_LOCALE_')
     headers = forget(request)
-    request.response.headers.extend(headers)
-    return HTTPFound(location=request.resource_url(context),
-                     headers=request.response.headers)
+    return HTTPFound(location=request.resource_url(context), headers=headers)
 
 
@@ -130,16 +73,12 @@
     renderer='ow:templates/signup.pt')
 def signup(context, request):
-    state = State(emails=context.lowercase_emails,
-                  names=context.lowercase_nicknames)
+    state = State(emails=context.lowercase_emails(),
+                  names=context.lowercase_usernames())
     form = Form(request, schema=SignUpSchema(), state=state)
 
     if 'submit' in request.POST and form.validate():
-        user = form.bind(User(), exclude=['password_confirm'])
-        user.verified = False
-        user.verification_token = get_verification_token()
-        context.add_user(user)
-        # send a verification link to the user email address
-        send_verification_email(request, user)
-        user.verification_tokens_sent += 1
+        username = request.POST['username']
+        user = form.bind(User(), exclude=['username', 'password_confirm'])
+        context[username] = user
         # Send to login
         return HTTPFound(location=request.resource_url(context))
@@ -151,61 +90,8 @@
 
 @view_config(
-    context=User,
-    name="verify",
-    renderer='ow:templates/verify.pt')
-def verify(context, request):
-    redirect_url = request.resource_url(context)
-
-    # user has been verified already, send to dashboard
-    if getattr(context, 'verified', False):
-        return HTTPFound(location=redirect_url)
-
-    # Look for a verification token, then check if we can verify the user with
-    # that token
-    verified = len(request.subpath) > 0
-    token = getattr(context, 'verification_token', False)
-    verified = verified and token and str(token) == request.subpath[0]
-    if verified:
-        # verified, log in automatically and send to the dashboard
-        context.verified = True
-        headers = remember(request, str(context.uid))
-        return HTTPFound(location=redirect_url, headers=headers)
-
-    # if we can not verify the user, show a page with some info about it
-    return {}
-
-
-@view_config(
-    context=User,
-    name="resend-verification-link")
-def resend_verification_link(context, request):
-    """
-    Send an email with the verification link, only if the user has not
-    been verified yet
-    """
-    # the message to be shown when the user gets back to the login page
-    query = {'message': 'already-verified'}
-    if not context.verified:
-        tokens_sent = getattr(context, 'verification_tokens_sent', 0)
-        if tokens_sent > 3:
-            # we already sent the token 3 times, we don't send it anymore
-            query = {'message': 'max-tokens-sent', 'email': context.email}
-        else:
-            if context.verification_token is None:
-                # for some reason the verification token is not there, get one
-                context.verification_token = get_verification_token()
-            send_verification_email(request, context)
-            context.verification_tokens_sent = tokens_sent + 1
-            query = {'message': 'link-sent', 'email': context.email}
-    # Send to login
-    url = request.resource_url(request.root, 'login', query=query)
-    return HTTPFound(location=url)
-
-
-@view_config(
     context=OpenWorkouts,
     name='forgot-password',
     renderer='ow:templates/forgot_password.pt')
-def recover_password(context, request):  # pragma: no cover
+def recover_password(context, request):
     # WIP
     Form(request)
@@ -220,47 +106,8 @@
     Render a dashboard for the current user
     """
-    # Look at the year we are viewing, if none is passed in the request,
-    # pick up the latest/newer available with activity
-    viewing_year = request.GET.get('year', None)
-    if viewing_year is None:
-        available_years = context.activity_years
-        if available_years:
-            viewing_year = available_years[0]
-    else:
-        # ensure this is an integer
-        viewing_year = int(viewing_year)
-
-    # Same for the month, if there is a year set
-    viewing_month = None
-    if viewing_year:
-        viewing_month = request.GET.get('month', None)
-        if viewing_month is None:
-            available_months = context.activity_months(viewing_year)
-            if available_months:
-                # we pick up the latest month available for the year,
-                # which means the current month in the current year
-                viewing_month = available_months[-1]
-        else:
-            # ensure this is an integer
-            viewing_month = int(viewing_month)
-
-    # pick up the workouts to be shown in the dashboard
-    workouts = context.workouts(viewing_year, viewing_month)
-
-    return {
-        'current_year': datetime.now(timezone.utc).year,
-        'current_day_name': datetime.now(timezone.utc).strftime('%a'),
-        'month_name': month_name,
-        'viewing_year': viewing_year,
-        'viewing_month': viewing_month,
-        'workouts': workouts
-    }
+    # Add here some logic
+    return {}
 
 
-@view_config(
-    context=OpenWorkouts,
-    name='profile',
-    permission='view',
-    renderer='ow:templates/profile.pt')
 @view_config(
     context=User,
@@ -273,58 +120,5 @@
     basic info, stats, etc
     """
-    if isinstance(context, OpenWorkouts):
-        nickname = request.subpath[0]
-        user = request.root.get_user_by_nickname(nickname)
-        if user is None:
-            return HTTPNotFound()
-    else:
-        user = context
-    now = datetime.now(timezone.utc)
-    year = int(request.GET.get('year', now.year))
-    month = int(request.GET.get('month', now.month))
-    week = request.GET.get('week', None)
-    # filter_by can be 'distance', 'time' or 'elevation', defaults to
-    # 'distance' if no value is provided
-    filter_by = request.GET.get('filter_by', 'distance')
-    workouts = user.workouts(year, month, week)
-    totals = {
-        'distance': Decimal(0),
-        'time': timedelta(0),
-        'elevation': Decimal(0)
-    }
-
-    for workout in workouts:
-        totals['distance'] += (
-            getattr(workout, 'distance', Decimal(0)) or Decimal(0))
-        totals['time'] += (
-            getattr(workout, 'duration', timedelta(0)) or timedelta(0))
-        totals['elevation'] += (
-            getattr(workout, 'uphill', Decimal(0)) or Decimal(0))
-
-    localizer = get_localizer(request)
-    user_gender = _('Unknown')
-    for g in get_gender_names():
-        if g[0] == user.gender:
-            user_gender = localizer.translate(g[1])
-
-    # get some data to be shown in the "profile stats" totals column
-    profile_stats = {
-        'sports': user.activity_sports,
-        'years': user.activity_years,
-        'current_year': request.GET.get('stats_year', now.year),
-        'current_sport': request.GET.get('stats_sport', user.favorite_sport),
-    }
-
-    return {
-        'user': user,
-        'user_gender': user_gender,
-        'workouts': workouts,
-        'current_month': '{year}-{month}'.format(
-            year=str(year), month=str(month).zfill(2)),
-        'current_week': week,
-        'totals': totals,
-        'profile_stats': profile_stats,
-        'filter_by': filter_by
-    }
+    return {}
 
 
@@ -334,22 +128,7 @@
     permission='view')
 def profile_picture(context, request):
-    if context.picture is None:
-        return HTTPNotFound()
-
-    size = request.GET.get('size', 0)
-    # we will need a tuple, it does not matter if both values are the same,
-    # Pillow will keep aspect ratio
-    size = (int(size), int(size))
-
-    image = Image.open(context.picture.open())
-
-    if size > (0, 0) and size < image.size:
-        # resize only if they are asking for smaller size, prevent
-        # someone asking for a "too big" image
-        image.thumbnail(size)
-
-    body_file = BytesIO()
-    image.save(body_file, format=image.format)
-    return Response(content_type='image', body=body_file.getvalue())
+    return Response(
+        content_type='image',
+        body_file=context.picture.open())
 
 
@@ -360,21 +139,5 @@
     renderer='ow:templates/edit_profile.pt')
 def edit_profile(context, request):
-    default_locale = request.registry.settings.get(
-        'pyramid.default_locale_name')
-    current_locale = request.cookies.get('_LOCALE_', default_locale)
-    # if not given a file there is an empty byte in POST, which breaks
-    # our blob storage validator.
-    # dirty fix until formencode fixes its api.is_empty method
-    if isinstance(request.POST.get('picture', None), bytes):
-        request.POST['picture'] = ''
-
-    nicknames = request.root.lowercase_nicknames
-    if context.nickname:
-        # remove the current user nickname from the list, preventing form
-        # validation error
-        nicknames.remove(context.nickname.lower())
-    state = State(emails=request.root.lowercase_emails, names=nicknames)
-    form = Form(request, schema=UserProfileSchema(), state=state, obj=context)
-
+    form = Form(request, schema=UserProfileSchema(), obj=context)
     if 'submit' in request.POST and form.validate():
         # No picture? do not override it
@@ -382,29 +145,10 @@
             del form.data['picture']
         form.bind(context)
-        # reindex
-        request.root.reindex(context)
-        # set the cookie for the locale/lang
-        request.response.set_cookie('_LOCALE_', form.data['locale'])
-        current_locale = form.data['locale']
         # Saved, send the user to the public view of her profile
-        return HTTPFound(location=request.resource_url(context, 'profile'),
-                         headers=request.response.headers)
-
+        return HTTPFound(location=request.resource_url(context, 'profile'))
     # prevent crashes on the form
     if 'picture' in form.data:
         del form.data['picture']
-
-    localizer = get_localizer(request)
-    gender_names = [
-        (g[0], localizer.translate(g[1])) for g in get_gender_names()]
-    available_locale_names = [
-        (l[0], localizer.translate(l[1])) for l in get_available_locale_names()
-    ]
-
-    return {'form': OWFormRenderer(form),
-            'timezones': common_timezones,
-            'gender_names': gender_names,
-            'available_locale_names': available_locale_names,
-            'current_locale': current_locale}
+    return {'form': OWFormRenderer(form)}
 
 
@@ -421,171 +165,2 @@
         return HTTPFound(location=request.resource_url(context, 'profile'))
     return {'form': OWFormRenderer(form)}
-
-
-@view_config(
-    context=User,
-    permission='view',
-    name='week')
-def week_stats(context, request):
-    localizer = get_localizer(request)
-    stats = context.week_stats
-    json_stats = []
-    for day in stats:
-        hms = timedelta_to_hms(stats[day]['time'])
-        name = localizer.translate(weekday_name[day.weekday()])[:3]
-        day_stats = {
-            'name': name,
-            'time': str(hms[0]).zfill(2),
-            'distance': int(round(stats[day]['distance'])),
-            'elevation': int(stats[day]['elevation']),
-            'workouts': stats[day]['workouts']
-        }
-        json_stats.append(day_stats)
-    return Response(content_type='application/json',
-                    charset='utf-8',
-                    body=json.dumps(json_stats))
-
-
-@view_config(
-    context=User,
-    permission='view',
-    name='month')
-def month_stats(context, request):
-    """
-    For the given month, return a json-encoded stream containing
-    per-day workouts information.
-    """
-    localizer = get_localizer(request)
-    now = datetime.now(timezone.utc)
-    year = int(request.GET.get('year', now.year))
-    month = int(request.GET.get('month', now.month))
-    workouts = context.workouts(year, month)
-    stats = {}
-
-    for workout in workouts:
-        start = workout.start.strftime('%Y-%m-%d')
-        if start not in stats.keys():
-            stats[start] = {
-                'time': 0,  # seconds
-                'distance': 0,  # kilometers
-                'elevation': 0,  # meters
-                'workouts': 0,
-                'sports': {},
-            }
-        duration = getattr(workout, 'duration', None) or timedelta(0)
-        stats[start]['time'] += duration.seconds
-        distance = getattr(workout, 'distance', None) or 0
-        stats[start]['distance'] += int(round(distance))
-        elevation = getattr(workout, 'uphill', None) or 0
-        stats[start]['elevation'] += int(elevation)
-        stats[start]['workouts'] += 1
-        if workout.sport not in stats[start]['sports'].keys():
-            stats[start]['sports'][workout.sport] = 0
-        stats[start]['sports'][workout.sport] += 1
-
-    json_stats = []
-    for day in stats.keys():
-        hms = timedelta_to_hms(timedelta(seconds=stats[day]['time']))
-        hours_label = _('hour')
-        if hms[0] > 1:
-            hours_label = _('hours')
-        time_formatted = ' '.join([
-            str(hms[0]).zfill(2), localizer.translate(hours_label),
-            str(hms[1]).zfill(2), localizer.translate(_('min.'))
-        ])
-        distance_formatted = str(round(stats[day]['distance'])) + ' km'
-        elevation_formatted = str(round(stats[day]['elevation'])) + ' m'
-        json_stats.append({
-            'day': day,
-            'time': stats[day]['time'],
-            'time_formatted': time_formatted,
-            'distance': stats[day]['distance'],
-            'distance_formatted': distance_formatted,
-            'elevation': stats[day]['elevation'],
-            'elevation_formatted': elevation_formatted,
-            'workouts': stats[day]['workouts'],
-            'sports': stats[day]['sports']
-        })
-
-    return Response(content_type='application/json',
-                    charset='utf-8',
-                    body=json.dumps(json_stats))
-
-
-@view_config(
-    context=User,
-    permission='view',
-    name='monthly')
-def last_months_stats(context, request):
-    """
-    Return a json-encoded stream with statistics for the last 12 months
-    """
-    localizer = get_localizer(request)
-    stats = context.yearly_stats
-    # this sets which month is 2 times in the stats, once this year, once
-    # the previous year. We will show it a bit different in the UI (showing
-    # the year too to prevent confusion)
-    repeated_month = datetime.now(timezone.utc).date().month
-    json_stats = []
-    for month in stats:
-        hms = timedelta_to_hms(stats[month]['time'])
-        name = localizer.translate(month_name[month[1]])[:3]
-        if month[1] == repeated_month:
-            name += ' ' + str(month[0])
-        month_stats = {
-            'id': str(month[0]) + '-' + str(month[1]).zfill(2),
-            'name': name,
-            'time': str(hms[0]).zfill(2),
-            'distance': int(round(stats[month]['distance'])),
-            'elevation': int(stats[month]['elevation']),
-            'workouts': stats[month]['workouts'],
-            'url': request.resource_url(
-                context, 'profile',
-                query={'year': str(month[0]), 'month': str(month[1])})
-        }
-        json_stats.append(month_stats)
-    return Response(content_type='application/json',
-                    charset='utf-8',
-                    body=json.dumps(json_stats))
-
-
-@view_config(
-    context=User,
-    permission='view',
-    name='weekly')
-def last_weeks_stats(context, request):
-    """
-    Return a json-encoded stream with statistics for the last 12-months, but
-    in a per-week basis
-    """
-    localizer = get_localizer(request)
-    stats = context.weekly_year_stats
-    # this sets which month is 2 times in the stats, once this year, once
-    # the previous year. We will show it a bit different in the UI (showing
-    # the year too to prevent confusion)
-    repeated_month = datetime.now(timezone.utc).date().month
-    json_stats = []
-    for week in stats:
-        hms = timedelta_to_hms(stats[week]['time'])
-        name = localizer.translate(month_name[week[1]])[:3]
-        if week[1] == repeated_month:
-            name += ' ' + str(week[0])
-        week_stats = {
-            'id': '-'.join(
-                [str(week[0]), str(week[1]).zfill(2), str(week[2])]),
-            'week': str(week[3]),  # the number of week in the current month
-            'name': name,
-            'time': str(hms[0]).zfill(2),
-            'distance': int(round(stats[week]['distance'])),
-            'elevation': int(stats[week]['elevation']),
-            'workouts': stats[week]['workouts'],
-            'url': request.resource_url(
-                context, 'profile',
-                query={'year': str(week[0]),
-                       'month': str(week[1]),
-                       'week': str(week[2])})
-        }
-        json_stats.append(week_stats)
-    return Response(content_type='application/json',
-                    charset='utf-8',
-                    body=json.dumps(json_stats))
Index: ow/views/workout.py
===================================================================
--- ow/views/workout.py	(revision 8c2b0949ae91540ee5c8101b9d5ff39003773da3)
+++ ow/views/workout.py	(revision 5ec3a0b5cf5640304a0953320daef2a28bbca9a5)
@@ -1,5 +1,3 @@
-from decimal import Decimal
 from datetime import datetime, timedelta, time, timezone
-import json
 
 import gpxpy
@@ -10,5 +8,4 @@
 from pyramid_simpleform import Form
 from pyramid_simpleform.renderers import FormRenderer
-from pyramid.i18n import TranslationStringFactory
 
 from ..schemas.workout import (
@@ -19,14 +16,10 @@
 from ..models.workout import Workout
 from ..models.user import User
-from ..utilities import slugify, save_map_screenshot, part_of_day
+from ..utilities import slugify
 from ..catalog import get_catalog, reindex_object, remove_from_catalog
 
 
-_ = TranslationStringFactory('OpenWorkouts')
-
-
 @view_config(
     context=User,
-    permission='edit',
     name='add-workout-manually',
     renderer='ow:templates/add_manual_workout.pt')
@@ -41,9 +34,6 @@
         # "bind" to the object, we do calculate both the full duration in
         # seconds and the full datetime "start" and we save that
-        #
-        # exclude also the distance field, we have to convert to decimal
-        # before adding it
         excluded = ['duration_hours', 'duration_minutes', 'duration_seconds',
-                    'start_date', 'start_time', 'distance']
+                    'start_date', 'start_time']
         workout = form.bind(Workout(), exclude=excluded)
         duration = timedelta(hours=form.data['duration_hours'],
@@ -58,10 +48,4 @@
                                  tzinfo=timezone.utc)
         workout.start = start
-        if not workout.title:
-            workout.title = part_of_day(start)
-            if workout.sport:
-                workout.title += ' ' + workout.sport
-            workout.title += ' ' + _('workout')
-        workout.distance = Decimal(form.data['distance'])
         context.add_workout(workout)
         return HTTPFound(location=request.resource_url(workout))
@@ -74,5 +58,4 @@
 @view_config(
     context=User,
-    permission='edit',
     name='add-workout',
     renderer='ow:templates/add_workout.pt')
@@ -81,14 +64,5 @@
     Add a workout uploading a tracking file
     """
-    # if not given a file there is an empty byte in POST, which breaks
-    # our blob storage validator.
-    # dirty fix until formencode fixes its api.is_empty method
-    if isinstance(request.POST.get('tracking_file', None), bytes):
-        request.POST['tracking_file'] = ''
-
     form = Form(request, schema=UploadedWorkoutSchema())
-
-    duplicate = None
-    allow_duplicates = request.POST.get('allow_duplicates') == 'on'
 
     if 'submit' in request.POST and form.validate():
@@ -101,30 +75,15 @@
         # Add basic info gathered from the file
         workout.load_from_file()
-        # Ensure this workout is not a duplicate of an existing workout.
-        #
-        # hashed is not "complete" for a workout that has not been added
-        # yet, as it does not have the owner set, so we have to "build it"
-        hashed = str(context.uid) + workout.hashed
-        duplicate = request.root.get_workout_by_hash(hashed)
-
-        if duplicate and not allow_duplicates:
-            form.errors['tracking_file'] = _(
-                'This workout looks like a duplicate of another workout, '
-                'please enable workout duplicates below to save it'
-            )
-        else:
-            # Add the workout
-            context.add_workout(workout)
-            return HTTPFound(location=request.resource_url(workout))
-
-    return {
-        'form': FormRenderer(form),
-        'duplicate': duplicate
-    }
-
-
-@view_config(
-    context=Workout,
-    permission='edit',
+        # Add the workout
+        context.add_workout(workout)
+        return HTTPFound(location=request.resource_url(workout))
+
+    return {
+        'form': FormRenderer(form)
+    }
+
+
+@view_config(
+    context=Workout,
     name='edit',
     renderer='ow:templates/edit_manual_workout.pt')
@@ -156,31 +115,18 @@
                                  tzinfo=timezone.utc)
         context.start = start
-        # ensure distance is a decimal
-        context.distance = Decimal(context.distance)
         catalog = get_catalog(context)
         reindex_object(catalog, context)
         return HTTPFound(location=request.resource_url(context))
 
-    # round some values before rendering
-    if form.data['distance']:
-        form.data['distance'] = round(form.data['distance'], 2)
-
-    return {
-        'form': FormRenderer(form)
-    }
-
-
-@view_config(
-    context=Workout,
-    permission='edit',
+    return {
+        'form': FormRenderer(form)
+    }
+
+
+@view_config(
+    context=Workout,
     name='update-from-file',
     renderer='ow:templates/update_workout_from_file.pt')
 def update_workout_from_file(context, request):
-    # if not given a file there is an empty byte in POST, which breaks
-    # our blob storage validator.
-    # dirty fix until formencode fixes its api.is_empty method
-    if isinstance(request.POST.get('tracking_file', None), bytes):
-        request.POST['tracking_file'] = ''
-
     form = Form(request, schema=UpdateWorkoutSchema())
     if 'submit' in request.POST and form.validate():
@@ -202,5 +148,4 @@
 @view_config(
     context=Workout,
-    permission='delete',
     name='delete',
     renderer='ow:templates/delete_workout.pt')
@@ -220,5 +165,4 @@
 @view_config(
     context=Workout,
-    permission='view',
     renderer='ow:templates/workout.pt')
 def workout(context, request):
@@ -249,7 +193,4 @@
     For now, simply return the gpx file if it has been attached to the
     workout.
-
-    This view requires no permission, as we access it from an non-authenticated
-    request in a separate job, to generate the static map screenshot.
     """
     if not context.has_gpx:
@@ -261,45 +202,2 @@
         content_disposition='attachment; filename="%s"' % gpx_slug,
         body_file=context.tracking_file.open())
-
-
-@view_config(
-    context=Workout,
-    name='map',
-    renderer='ow:templates/workout-map.pt')
-def workout_map(context, request):
-    """
-    Render a page that has only a map with tracking info.
-    This view requires no permission, as we access it from an non-authenticated
-    request in a separate job, to generate the static map screenshot.
-    """
-    start_point = {}
-    if context.has_gpx:
-        with context.tracking_file.open() as gpx_file:
-            gpx_contents = gpx_file.read()
-            gpx_contents = gpx_contents.decode('utf-8')
-            gpx = gpxpy.parse(gpx_contents)
-            if gpx.tracks:
-                track = gpx.tracks[0]
-                center_point = track.get_center()
-                start_point = {'latitude': center_point.latitude,
-                               'longitude': center_point.longitude,
-                               'elevation': center_point.elevation}
-    return {'start_point': start_point}
-
-
-@view_config(
-    context=Workout,
-    permission='edit',
-    name='map-shot')
-def workout_map_shot(context, request):
-    """
-    Ask for the screenshot of a map, creating one if it does not exist.
-    A json object is returned, containing the info for the needed screenshot
-    """
-    if context.map_screenshot is None:
-        save_map_screenshot(context, request)
-
-    info = {'url': request.static_url(context.map_screenshot)}
-    return Response(content_type='application/json',
-                    charset='utf-8',
-                    body=json.dumps(info))
