Exemple #1
0
    def get(self, relpath):
        output = []

        if relpath == "authors":
            profiles = {}
            for p in models.get_sorted_profiles():  # This query is memcached.
                profile_id = p["id"]
                profiles[profile_id] = p
                geo_location = profiles[profile_id]["geo_location"]
                profiles[profile_id]["geo_location"] = str(geo_location)
            output = profiles
        elif relpath == "tutorials":
            output = TagsHandler()._query_to_serializable_list(TagsHandler().get_as_db("type:tutorial"))
        elif relpath == "articles":
            output = TagsHandler()._query_to_serializable_list(TagsHandler().get_as_db("type:article"))
        elif relpath == "casestudies":
            output = TagsHandler()._query_to_serializable_list(TagsHandler().get_as_db("type:casestudy"))
        elif relpath == "demos":
            output = TagsHandler()._query_to_serializable_list(TagsHandler().get_as_db("type:demo"))
        elif relpath == "samples":
            output = TagsHandler()._query_to_serializable_list(TagsHandler().get_as_db("type:sample"))
        elif relpath == "presentations":
            output = TagsHandler()._query_to_serializable_list(TagsHandler().get_as_db("type:presentation"))
        elif relpath == "announcements":
            output = TagsHandler()._query_to_serializable_list(TagsHandler().get_as_db("type:announcement"))
        elif relpath == "videos":
            output = TagsHandler()._query_to_serializable_list(TagsHandler().get_as_db("type:video"))

        self.response.headers.add_header("Access-Control-Allow-Origin", "*")
        self.response.headers["Content-Type"] = "application/json"
        self.response.out.write(simplejson.dumps(output))
Exemple #2
0
    def post(self, relpath):

        if relpath == 'live':
            # Get first (and only) result.
            live_data = models.LiveData.all().get()
            if live_data is None:
                live_data = models.LiveData()

            live_data.gdl_page_url = self.request.get('gdl_page_url') or None

            #if live_data.gdl_page_url is not None:
            live_data.put()

            return self.redirect('/database/live')

        elif relpath == 'author':
            try:
                given_name = self.request.get('given_name')
                family_name = self.request.get('family_name')
                author = models.Author(
                    key_name=''.join([given_name, family_name]).lower(),
                    given_name=given_name,
                    family_name=family_name,
                    org=self.request.get('org'),
                    unit=self.request.get('unit'),
                    city=self.request.get('city'),
                    state=self.request.get('state'),
                    country=self.request.get('country'),
                    homepage=self.request.get('homepage') or None,
                    google_account=self.request.get('google_account') or None,
                    twitter_account=self.request.get('twitter_account')
                    or None,
                    email=self.request.get('email') or None,
                    lanyrd=self.request.get('lanyrd') == 'on')
                lat = self.request.get('lat')
                lon = self.request.get('lon')
                if lat and lon:
                    author.geo_location = db.GeoPt(float(lat), float(lon))

                author.put()

            except db.Error, e:
                # TODO: Doesn't repopulate lat/lng or return errors for it.
                form = models.AuthorForm(self.request.POST)
                if not form.is_valid():
                    sorted_profiles = models.get_sorted_profiles(
                        update_cache=True)
                    template_data = {
                        'sorted_profiles': sorted_profiles,
                        'profile_amount': len(sorted_profiles),
                        'author_form': form
                    }
                    return self.render(
                        data=template_data,
                        template_path='database/author_new.html',
                        relpath=relpath)
            else:
                self.redirect('/database/author')
Exemple #3
0
  def post(self, relpath):

    if relpath == 'live':
      # Get first (and only) result.
      live_data = models.LiveData.all().get()
      if live_data is None:
        live_data = models.LiveData()

      live_data.gdl_page_url = self.request.get('gdl_page_url') or None

      #if live_data.gdl_page_url is not None:
      live_data.put()

      return self.redirect('/database/live')

    elif relpath == 'author':
      try:
        given_name = self.request.get('given_name')
        family_name = self.request.get('family_name')
        author = models.Author(
            key_name=''.join([given_name, family_name]).lower(),
            given_name=given_name,
            family_name=family_name,
            org=self.request.get('org'),
            unit=self.request.get('unit'),
            city=self.request.get('city'),
            state=self.request.get('state'),
            country=self.request.get('country'),
            homepage=self.request.get('homepage') or None,
            google_account=self.request.get('google_account') or None,
            twitter_account=self.request.get('twitter_account') or None,
            email=self.request.get('email') or None,
            lanyrd=self.request.get('lanyrd') == 'on')
        lat = self.request.get('lat')
        lon = self.request.get('lon')
        if lat and lon:
          author.geo_location = db.GeoPt(float(lat), float(lon))

        author.put()

      except db.Error, e:
        # TODO: Doesn't repopulate lat/lng or return errors for it.
        form = models.AuthorForm(self.request.POST)
        if not form.is_valid():
          sorted_profiles = models.get_sorted_profiles(update_cache=True)
          template_data = {
            'sorted_profiles': sorted_profiles,
            'profile_amount': len(sorted_profiles),
            'author_form': form
          }
          return self.render(data=template_data,
                             template_path='database/author_new.html',
                             relpath=relpath)
      else:
        self.redirect('/database/author')
Exemple #4
0
    def post(self, relpath):

        if relpath == "live":
            # Get first (and only) result.
            live_data = models.LiveData.all().get()
            if live_data is None:
                live_data = models.LiveData()

            live_data.gdl_page_url = self.request.get("gdl_page_url") or None

            # if live_data.gdl_page_url is not None:
            live_data.put()

            return self.redirect("/database/live")

        elif relpath == "author":
            try:
                given_name = self.request.get("given_name")
                family_name = self.request.get("family_name")
                author = models.Author(
                    key_name="".join([given_name, family_name]).lower(),
                    given_name=given_name,
                    family_name=family_name,
                    org=self.request.get("org"),
                    unit=self.request.get("unit"),
                    city=self.request.get("city"),
                    state=self.request.get("state"),
                    country=self.request.get("country"),
                    homepage=self.request.get("homepage") or None,
                    google_account=self.request.get("google_account") or None,
                    twitter_account=self.request.get("twitter_account") or None,
                    email=self.request.get("email") or None,
                    lanyrd=self.request.get("lanyrd") == "on",
                )
                lat = self.request.get("lat")
                lon = self.request.get("lon")
                if lat and lon:
                    author.geo_location = db.GeoPt(float(lat), float(lon))

                author.put()

            except db.Error, e:
                # TODO: Doesn't repopulate lat/lng or return errors for it.
                form = models.AuthorForm(self.request.POST)
                if not form.is_valid():
                    sorted_profiles = models.get_sorted_profiles(update_cache=True)
                    template_data = {
                        "sorted_profiles": sorted_profiles,
                        "profile_amount": len(sorted_profiles),
                        "author_form": form,
                    }
                    return self.render(data=template_data, template_path="database/author_new.html", relpath=relpath)
            else:
                self.redirect("/database/author")
Exemple #5
0
    def get(self, relpath):
        output = []

        if relpath == 'authors':
            profiles = {}
            for p in models.get_sorted_profiles():  # This query is memcached.
                profile_id = p['id']
                profiles[profile_id] = p
                geo_location = profiles[profile_id]['geo_location']
                profiles[profile_id]['geo_location'] = str(geo_location)
            output = profiles
        elif relpath == 'tutorials':
            output = TagsHandler()._query_to_serializable_list(
                TagsHandler().get_as_db('type:tutorial'))
        elif relpath == 'articles':
            output = TagsHandler()._query_to_serializable_list(
                TagsHandler().get_as_db('type:article'))
        elif relpath == 'casestudies':
            output = TagsHandler()._query_to_serializable_list(
                TagsHandler().get_as_db('type:casestudy'))
        elif relpath == 'demos':
            output = TagsHandler()._query_to_serializable_list(
                TagsHandler().get_as_db('type:demo'))
        elif relpath == 'samples':
            output = TagsHandler()._query_to_serializable_list(
                TagsHandler().get_as_db('type:sample'))
        elif relpath == 'presentations':
            output = TagsHandler()._query_to_serializable_list(
                TagsHandler().get_as_db('type:presentation'))
        elif relpath == 'announcements':
            output = TagsHandler()._query_to_serializable_list(
                TagsHandler().get_as_db('type:announcement'))
        elif relpath == 'videos':
            output = TagsHandler()._query_to_serializable_list(
                TagsHandler().get_as_db('type:video'))

        self.response.headers.add_header('Access-Control-Allow-Origin', '*')
        self.response.headers['Content-Type'] = 'application/json'
        self.response.out.write(simplejson.dumps(output))
Exemple #6
0
  def get(self, relpath):
    output = []

    if relpath == 'authors':
      profiles = {}
      for p in models.get_sorted_profiles(): # This query is memcached.
        profile_id = p['id']
        profiles[profile_id] = p
        geo_location = profiles[profile_id]['geo_location']
        profiles[profile_id]['geo_location'] = str(geo_location)
      output = profiles
    elif relpath == 'tutorials':
      output = TagsHandler()._query_to_serializable_list(
         TagsHandler().get_as_db('type:tutorial'))
    elif relpath == 'articles':
      output = TagsHandler()._query_to_serializable_list(
          TagsHandler().get_as_db('type:article'))
    elif relpath == 'casestudies':
      output = TagsHandler()._query_to_serializable_list(
          TagsHandler().get_as_db('type:casestudy'))
    elif relpath == 'demos':
      output = TagsHandler()._query_to_serializable_list(
          TagsHandler().get_as_db('type:demo'))
    elif relpath == 'samples':
      output = TagsHandler()._query_to_serializable_list(
          TagsHandler().get_as_db('type:sample'))
    elif relpath == 'presentations':
      output = TagsHandler()._query_to_serializable_list(
          TagsHandler().get_as_db('type:presentation'))
    elif relpath == 'announcements':
      output = TagsHandler()._query_to_serializable_list(
          TagsHandler().get_as_db('type:announcement'))
    elif relpath == 'videos':
      output = TagsHandler()._query_to_serializable_list(
          TagsHandler().get_as_db('type:video'))

    self.response.headers.add_header('Access-Control-Allow-Origin', '*')
    self.response.headers['Content-Type'] = 'application/json'
    self.response.out.write(simplejson.dumps(output))
Exemple #7
0
    def get(self, relpath, post_id=None):
        self._set_cache_param()

        if (relpath == 'live'):
            user = users.get_current_user()

            # Restrict access to this page to admins and whitelisted users.
            if (not users.is_current_user_admin()
                    and user.email() not in settings.WHITELISTED_USERS):
                return self.redirect('/')

            entity = models.LiveData.all().get()
            if entity:
                live_form = models.LiveForm(
                    entity.to_dict(),
                    initial={'gdl_page_url': entity.gdl_page_url})
            else:
                live_form = models.LiveForm()

            template_data = {'live_form': live_form}
            return self.render(data=template_data,
                               template_path='database/live.html',
                               relpath=relpath)

        elif (relpath == 'author'):
            # adds a new author information into DataStore.
            sorted_profiles = models.get_sorted_profiles(update_cache=True)
            template_data = {
                'sorted_profiles': sorted_profiles,
                'profile_amount': len(sorted_profiles),
                'author_form': models.AuthorForm()
            }
            return self.render(data=template_data,
                               template_path='database/author_new.html',
                               relpath=relpath)

        elif (relpath == 'drop_all'):
            if settings.PROD:
                return self.response.out.write(
                    'Handler not allowed in production.')
            self._NukeDB()

        elif (relpath == 'load_tutorials'):
            if settings.PROD:
                return self.response.out.write(
                    'Handler not allowed in production.')
            self._AddTestResources()

        elif (relpath == 'load_authors'):
            if settings.PROD:
                return self.response.out.write(
                    'Handler not allowed in production.')
            self._AddTestAuthors()

        elif (relpath == 'load_playground_samples'):
            if settings.PROD:
                return self.response.out.write(
                    'Handler not allowed in production.')
            self._AddTestPlaygroundSamples()

        elif (relpath == 'load_studio_samples'):
            if settings.PROD:
                return self.response.out.write(
                    'Handler not allowed in production.')
            self._AddTestStudioSamples()

        elif (relpath == 'load_all'):
            if settings.PROD:
                return self.response.out.write(
                    'Handler not allowed in production.')

            # TODO(ericbidelman): Make this async.
            self._AddTestAuthors()
            self._AddTestResources()
            self._AddTestPlaygroundSamples()
            self._AddTestStudioSamples()

        elif relpath == 'resource':
            tutorial_form = models.TutorialForm()

            if post_id:  # /database/resource/1234
                post = models.Resource.get_by_id(int(post_id))
                if post:
                    author_id = post.author.key().name()
                    second_author_id = (post.second_author
                                        and post.second_author.key().name())

                    # Adjust browser support so it renders to the checkboxes correctly.
                    browser_support = [
                        b.capitalize() for b in post.browser_support
                    ]
                    for b in browser_support:
                        if len(b) == 2:
                            browser_support[browser_support.index(
                                b)] = b.upper()

                    form_data = post.to_dict()
                    form_data['tags'] = ', '.join(post.tags)
                    form_data['author'] = author_id
                    form_data['second_author'] = second_author_id or author_id
                    form_data['browser_support'] = browser_support

                    tutorial_form = models.TutorialForm(form_data)

            template_data = {
                'tutorial_form':
                tutorial_form,
                # get_all() not used b/c we don't care about caching on this page.
                'resources':
                (models.Resource.all().order('-publication_date').fetch(
                    limit=settings.MAX_FETCH_LIMIT)),
                'post_id':
                post_id and int(post_id) or ''
            }
            return self.render(data=template_data,
                               template_path='database/resource_new.html',
                               relpath=relpath)

        # Catch all to redirect to proper page.
        return self.redirect('/database/resource')
Exemple #8
0
    def get(self, relpath):

        self._set_cache_param()

        # Handle bug redirects before anything else, as it's trivial.
        if relpath == 'new-bug':
            return self.redirect(
                'https://github.com/html5rocks/www.html5rocks.com/issues/new')

        # Handle humans before locale, to prevent redirect to /en/
        # (but still ensure it's dynamic, ie we can't just redirect to a static url)
        if relpath == 'humans.txt':
            self.response.headers['Content-Type'] = 'text/plain'
            sorted_profiles = models.get_sorted_profiles()
            return self.render(data={
                'sorted_profiles': sorted_profiles,
                'profile_amount': len(sorted_profiles)
            },
                               template_path='content/humans.txt',
                               relpath=relpath)

        # Get the locale: if it's "None", redirect to English
        locale = self.get_language()
        if not locale:
            return self.redirect("/en/%s" % relpath, permanent=True)

        # If there is a locale specified but it has no leading slash, redirect
        if not relpath.startswith("%s/" % locale):
            return self.redirect("/%s/" % locale, permanent=True)

        # If we get here, is because the language is specified correctly,
        # so let's activate it
        self.activate_language(locale)

        # Strip off leading `/[en|de|fr|...]/`
        relpath = re.sub('^/?\w{2,3}(?:/)?', '', relpath)

        # Are we looking for a feed?
        is_feed = self.request.path.endswith('.xml')

        # Which CSS should this use? (Will get overwritten.)
        css_file = 'base'
        page_class = None
        include_home_link = True

        # Setup handling of redirected article URLs: If a user tries to access an
        # article from a non-supported language, we'll redirect them to the
        # English version (assuming it exists), with a `redirect_from_locale` GET
        # param.
        redirect_from_locale = self.request.get('redirect_from_locale', '')
        if not re.match('[a-zA-Z]{2,3}$', redirect_from_locale):
            redirect_from_locale = False
        else:
            translation.activate(redirect_from_locale)
            redirect_from_locale = {
                'lang':
                redirect_from_locale,
                'msg':
                _('Sorry, this article isn\'t available in your native '
                  'language; we\'ve redirected you to the English version.')
            }
            translation.activate(locale)

        # Landing page or /tutorials|features|mobile|gaming|business\/?
        if ((relpath == '' or relpath[-1] == '/') or  # Landing page.
            (relpath[-1] != '/' and relpath in [
                'mobile', 'tutorials', 'features', 'gaming', 'business',
                'updates'
            ])):

            # Check if path ends with a / and adds if necessary
            if (relpath != '' and relpath[-1] != '/'
                    and self.request.query_string == ''):
                return self.redirect(relpath + '/', permanent=True)
            # Check if path ends with a / and adds along with the query string
            elif (relpath != '' and relpath[-1] != '/'
                  and self.request.query_string != ''):
                return self.redirect(relpath + '/?' +
                                     self.request.query_string,
                                     permanent=True)

            if (relpath == ''):
                include_home_link = None
                css_file = 'v2-combined'

            if (relpath == 'tutorials/'):
                css_file = 'v2-combined'
                page_class = 'article tutorial listing'

            path = os.path.join('content', relpath, 'index.html')
        else:
            path = os.path.join('content', relpath)

        # Render the .html page if it exists. Otherwise, check that the Atom feed
        # the user is requesting has a corresponding .html page that exists.

        if (relpath == 'profiles' or relpath == 'profiles/'):
            profiles = models.get_sorted_profiles()
            for p in profiles:
                p['tuts_by_author'] = models.Resource.get_tutorials_by_author(
                    p['id'])
            return self.render(data={
                'include_home_link': include_home_link,
                'page_class': page_class,
                'css_file': css_file,
                'sorted_profiles': profiles
            },
                               template_path='content/profiles.html',
                               relpath=relpath)
        elif ((re.search('tutorials/.+', relpath) or re.search(
                'mobile/.+', relpath) or re.search('gaming/.+', relpath)
               or re.search('business/.+', relpath)
               or re.search('updates/.+', relpath)
               or re.search('tutorials/casestudies/.+', relpath))
              and not is_feed):
            # If this is an old-style mobile article or case study, redirect to the
            # new style.
            match = re.search(('(?P<type>mobile|tutorials/casestudies)'
                               '/(?P<slug>[a-z-_0-9]+).html$'), relpath)
            if match:
                return self.redirect(
                    '/%s/%s/%s/' %
                    (locale, match.group('type'), match.group('slug')))

            # If no trailing / (e.g. /tutorials/blah), redirect to /tutorials/blah/.
            if (relpath[-1] != '/' and not relpath.endswith('.html')):
                return self.redirect(self.request.url + '/')

            # Tutorials look like this on the filesystem:
            #
            #   .../tutorials +
            #                 |
            #                 +-- article-slug  +
            #                 |                 |
            #                 |                 +-- en  +
            #                 |                 |       |
            #                 |                 |       +-- index.html
            #                 ...
            #
            # So, to determine if an HTML page exists for the requested language
            # `split` the file's path, add in the locale, and check existence:
            (dir, filename) = os.path.split(path)
            if os.path.isfile(os.path.join(dir, locale, filename)):
                # Lookup tutorial by its url. Return the first one that matches.
                # get_all() not used because we don't care about caching on individual
                # tut page.
                tut = models.Resource.all().filter('url =',
                                                   '/' + relpath).get()

                # Localize title and description.
                if tut:
                    if tut.title:
                        tut.title = _(tut.title)
                    if hasattr(tut, 'subtitle') and tut.subtitle:
                        tut.subtitle = _(tut.subtitle)
                    if tut.description:
                        tut.description = _(tut.description)

                css_file = 'v2-combined'
                page_class = 'article tutorial'

                # Gather list of localizations by globbing matching directories, then
                # stripping out the current locale and 'static'. Once we have a list,
                # convert it to a series of dictionaries containing the localization's
                # path and name:
                langs = {
                    'de': 'Deutsch',
                    'en': 'English',
                    'fr': 'Français',
                    'es': 'Español',
                    'it': 'Italiano',
                    'ja': '日本語',
                    'ko': '한국어',
                    'pt': 'Português (Brasil)',
                    'ru': 'Pусский',
                    'zh': '中文 (简体)'
                }
                loc_list = []
                for d in glob.glob(os.path.join(dir, '*', 'index.html')):
                    loc = os.path.basename(os.path.dirname(d))
                    if loc not in [locale, 'static']:
                        loc_list.append({
                            'path': '/%s/%s' % (loc, relpath),
                            'lang': langs[loc],
                            'loc': loc
                        })

                data = {
                    'include_home_link': include_home_link,
                    'page_class': page_class,
                    'css_file': css_file,
                    'tut': tut,
                    'localizations': loc_list,
                    'redirect_from_locale': redirect_from_locale
                }
                return self.render(template_path=os.path.join(
                    dir, locale, filename),
                                   data=data,
                                   relpath=relpath)

            # If the localized file doesn't exist, and the locale isn't English, look
            # for an english version of the file, and redirect the user there if
            # it's found:
            elif os.path.isfile(os.path.join(dir, 'en', filename)):
                return self.redirect("/en/%s?redirect_from_locale=%s" %
                                     (relpath, locale))
        elif os.path.isfile(path):
            #TODO(ericbidelman): Don't need these tutorial/update results for query.

            page_number = int(self.request.get('page',
                                               default_value=0)) or None
            template_args = dict()

            if page_number:
                template_args['previous_page'] = page_number - 1
                template_args['next_page'] = page_number + 1

            if relpath[:-1] in ['mobile', 'gaming', 'business']:
                results = TagsHandler().get_as_db(
                    relpath[:-1], limit=self.FEATURE_PAGE_WHATS_NEW_LIMIT)
            elif relpath == 'updates':
                results = []
            else:
                include_updates = None
                if relpath == '':
                    resource_limit = 9
                    include_updates = True
                else:
                    resource_limit = None

                if page_number is not None:
                    results = models.Resource.get_all(
                        order='-publication_date',
                        page=page_number,
                        include_updates=include_updates)
                else:
                    results = models.Resource.get_all(
                        order='-publication_date',
                        limit=resource_limit,
                        include_updates=include_updates)

            tutorials = []  # List of final result set.
            authors = []  # List of authors related to the result set.
            for r in results:
                resource_type = [x for x in r.tags if x.startswith('type:')]
                if len(resource_type):
                    resource_type = resource_type[0].replace('type:', '')

                if r.url.startswith('/'):
                    # Localize title and description if article is localized.
                    filepath = os.path.join(self.BASEDIR, 'content', r.url[1:],
                                            self.locale, 'index.html')
                    if os.path.isfile(filepath):
                        if r.title:
                            r.title = _(r.title)
                        if hasattr(r, 'subtitle') and r.subtitle:
                            r.subtitle = _(r.subtitle)
                        if r.description:
                            r.description = _(r.description)
                    # Point the article to the localized version, regardless.
                    r.url = "/%s%s" % (self.locale, r.url)

                tutorials.append(r)
                tutorials[-1].classes = [
                    x.replace('class:', '') for x in r.tags
                    if x.startswith('class:')
                ]
                tutorials[-1].tags = [
                    x for x in r.tags
                    if not (x.startswith('class:') or x.startswith('type:'))
                ]
                tutorials[-1].type = resource_type

                #TODO(ericbidelman): Probably don't need author for every result query.
                authors.append(r.author)

            # Remove duplicate authors from the list.
            author_dict = {}
            for a in authors:
                if a is not None:
                    author_dict[a.key().name()] = a
            authors = author_dict.values()

            data = {
                'include_home_link': include_home_link,
                'page_class': page_class,
                'css_file': css_file,
                'tutorials': tutorials,
                'authors': authors,
                'args': template_args
            }

            return self.render(data, template_path=path, relpath=relpath)

        elif os.path.isfile(path[:path.rfind('.')] + '.html'):
            return self.render(data={'css_file': css_file},
                               template_path=path[:path.rfind('.')] + '.html',
                               relpath=relpath)

        elif os.path.isfile(path + '.html'):

            page_title = None
            if path == 'content/style-guide':
                css_file = 'v2-combined'
                page_class = 'article'
                page_title = 'Style Guide'

            category = relpath.replace('features/', '')
            updates = TagsHandler().get_as_db(
                'class:' + category, limit=self.FEATURE_PAGE_WHATS_NEW_LIMIT)
            for r in updates:
                if r.url.startswith('/'):
                    # Localize title if article is localized.
                    filepath = os.path.join(self.BASEDIR, 'content', r.url[1:],
                                            self.locale, 'index.html')
                    if r.url.startswith('/') and os.path.isfile(
                            filepath) and r.title:
                        r.title = _(r.title)
                    # Point the article to the localized version, regardless.
                    r.url = "/%s%s" % (self.locale, r.url)

            data = {
                'include_home_link': include_home_link,
                'page_title': page_title,
                'page_class': page_class,
                'css_file': css_file,
                'category': category,
                'updates': updates
            }
            if relpath == 'why':
                if os.path.isfile(os.path.join(path, locale, 'index.html')):
                    data['local_content_path'] = os.path.join(
                        relpath, locale, 'index.html')
                else:
                    data['local_content_path'] = os.path.join(
                        relpath, 'en', 'index.html')

            return self.render(data=data,
                               template_path=path + '.html',
                               relpath=relpath)

        # If we've reached here, assume 404.
        return self.render(status=404,
                           message='Page Not Found',
                           template_path='404.html')
Exemple #9
0
  def get(self, relpath, post_id=None):
    self._set_cache_param()

    if (relpath == 'live'):
      user = users.get_current_user()

      # Restrict access to this page to admins and whitelisted users.
      if (not users.is_current_user_admin() and
          user.email() not in settings.WHITELISTED_USERS):
        return self.redirect('/')

      entity = models.LiveData.all().get()
      if entity:
        live_form = models.LiveForm(entity.to_dict(), initial={
            'gdl_page_url': entity.gdl_page_url
            })
      else:
        live_form = models.LiveForm()

      template_data = {
        'live_form': live_form
      }
      return self.render(data=template_data,
                         template_path='database/live.html',
                         relpath=relpath)

    elif (relpath == 'author'):
      # adds a new author information into DataStore.
      sorted_profiles = models.get_sorted_profiles(update_cache=True)
      template_data = {
        'sorted_profiles': sorted_profiles,
        'profile_amount': len(sorted_profiles),
        'author_form': models.AuthorForm()
      }
      return self.render(data=template_data,
                         template_path='database/author_new.html',
                         relpath=relpath)

    elif (relpath == 'drop_all'):
      if settings.PROD:
        return self.response.out.write('Handler not allowed in production.')
      self._NukeDB()

    elif (relpath == 'load_tutorials'):
      if settings.PROD:
        return self.response.out.write('Handler not allowed in production.')
      self._AddTestResources()

    elif (relpath == 'load_authors'):
      if settings.PROD:
        return self.response.out.write('Handler not allowed in production.')
      self._AddTestAuthors()

    elif (relpath == 'load_playground_samples'):
      if settings.PROD:
        return self.response.out.write('Handler not allowed in production.')
      self._AddTestPlaygroundSamples()

    elif (relpath == 'load_studio_samples'):
      if settings.PROD:
        return self.response.out.write('Handler not allowed in production.')
      self._AddTestStudioSamples()

    elif (relpath == 'load_all'):
      if settings.PROD:
        return self.response.out.write('Handler not allowed in production.')

      # TODO(ericbidelman): Make this async.
      self._AddTestAuthors()
      self._AddTestResources()
      self._AddTestPlaygroundSamples()
      self._AddTestStudioSamples()

    elif relpath == 'resource':
      tutorial_form = models.TutorialForm()

      if post_id: # /database/resource/1234
        post = models.Resource.get_by_id(int(post_id))
        if post:
          author_id = post.author.key().name()
          second_author_id = (post.second_author and
                              post.second_author.key().name())

          # Adjust browser support so it renders to the checkboxes correctly.
          browser_support = [b.capitalize() for b in post.browser_support]
          for b in browser_support:
            if len(b) == 2:
              browser_support[browser_support.index(b)] = b.upper()

          form_data = post.to_dict()
          form_data['tags'] = ', '.join(post.tags)
          form_data['author'] = author_id
          form_data['second_author'] = second_author_id or author_id
          form_data['browser_support'] = browser_support

          tutorial_form = models.TutorialForm(form_data)

      template_data = {
        'tutorial_form': tutorial_form,
        # get_all() not used b/c we don't care about caching on this page.
        'resources': (models.Resource.all().order('-publication_date')
                                     .fetch(limit=settings.MAX_FETCH_LIMIT)),
        'post_id': post_id and int(post_id) or ''
      }
      return self.render(data=template_data,
                         template_path='database/resource_new.html',
                         relpath=relpath)

    # Catch all to redirect to proper page.
    return self.redirect('/database/resource')
Exemple #10
0
  def get(self, relpath):

    self._set_cache_param()

    # Handle bug redirects before anything else, as it's trivial.
    if relpath == 'new-bug':
      return self.redirect('https://github.com/html5rocks/www.html5rocks.com/issues/new')

    # Handle humans before locale, to prevent redirect to /en/
    # (but still ensure it's dynamic, ie we can't just redirect to a static url)
    if relpath == 'humans.txt':
      self.response.headers['Content-Type'] = 'text/plain'
      sorted_profiles = models.get_sorted_profiles()
      return self.render(data={'sorted_profiles': sorted_profiles,
                               'profile_amount': len(sorted_profiles)},
                         template_path='content/humans.txt',
                         relpath=relpath)

    # Get the locale: if it's "None", redirect to English
    locale = self.get_language()
    if not locale:
      return self.redirect("/en/%s" % relpath, permanent=True)

    # If there is a locale specified but it has no leading slash, redirect
    if not relpath.startswith("%s/" % locale):
      return self.redirect("/%s/" % locale, permanent=True)

    # If we get here, is because the language is specified correctly,
    # so let's activate it
    self.activate_language(locale)

    # Strip off leading `/[en|de|fr|...]/`
    relpath = re.sub('^/?\w{2,3}(?:/)?', '', relpath)

    # Are we looking for a feed?
    is_feed = self.request.path.endswith('.xml')

    # Which CSS should this use? (Will get overwritten.)
    css_file = 'base'

    # Setup handling of redirected article URLs: If a user tries to access an
    # article from a non-supported language, we'll redirect them to the
    # English version (assuming it exists), with a `redirect_from_locale` GET
    # param.
    redirect_from_locale = self.request.get('redirect_from_locale', '')
    if not re.match('[a-zA-Z]{2,3}$', redirect_from_locale):
      redirect_from_locale = False
    else:
      translation.activate(redirect_from_locale)
      redirect_from_locale = {
        'lang': redirect_from_locale,
        'msg': _('Sorry, this article isn\'t available in your native '
                 'language; we\'ve redirected you to the English version.')
      }
      translation.activate(locale)

    # Landing page or /tutorials|features|mobile|gaming|business\/?
    if ((relpath == '' or relpath[-1] == '/') or  # Landing page.
        (relpath[-1] != '/' and relpath in ['mobile', 'tutorials', 'features',
                                            'gaming', 'business', 'updates'])):

      # Check if path ends with a / and adds if necessary
      if (relpath != '' and relpath[-1] != '/' and
        self.request.query_string == ''):
          return self.redirect(relpath + '/', permanent=True)
      # Check if path ends with a / and adds along with the query string
      elif (relpath != '' and relpath[-1] != '/' and
        self.request.query_string != ''):
          return self.redirect(relpath + '/?' + self.request.query_string,
                               permanent=True)

      if (relpath == ''):
        css_file = 'home'

      path = os.path.join('content', relpath, 'index.html')
    else:
      path = os.path.join('content', relpath)

    # Render the .html page if it exists. Otherwise, check that the Atom feed
    # the user is requesting has a corresponding .html page that exists.

    if (relpath == 'profiles' or relpath == 'profiles/'):
      profiles = models.get_sorted_profiles()
      for p in profiles:
        p['tuts_by_author'] = models.Resource.get_tutorials_by_author(p['id'])
      return self.render(data={
            'css_file':css_file,
            'sorted_profiles': profiles
          }, template_path='content/profiles.html', relpath=relpath)
    elif ((re.search('tutorials/.+', relpath) or
           re.search('mobile/.+', relpath) or
           re.search('gaming/.+', relpath) or
           re.search('business/.+', relpath) or
           re.search('updates/.+', relpath) or
           re.search('tutorials/casestudies/.+', relpath))
          and not is_feed):
      # If this is an old-style mobile article or case study, redirect to the
      # new style.
      match = re.search(('(?P<type>mobile|tutorials/casestudies)'
                         '/(?P<slug>[a-z-_0-9]+).html$'), relpath)
      if match:
        return self.redirect('/%s/%s/%s/' % (locale, match.group('type'),
                                             match.group('slug')))

      # If no trailing / (e.g. /tutorials/blah), redirect to /tutorials/blah/.
      if (relpath[-1] != '/' and not relpath.endswith('.html')):
        return self.redirect(self.request.url + '/')

      # Tutorials look like this on the filesystem:
      #
      #   .../tutorials +
      #                 |
      #                 +-- article-slug  +
      #                 |                 |
      #                 |                 +-- en  +
      #                 |                 |       |
      #                 |                 |       +-- index.html
      #                 ...
      #
      # So, to determine if an HTML page exists for the requested language
      # `split` the file's path, add in the locale, and check existence:
      (dir, filename) = os.path.split(path)
      if os.path.isfile(os.path.join(dir, locale, filename)):
        # Lookup tutorial by its url. Return the first one that matches.
        # get_all() not used because we don't care about caching on individual
        # tut page.
        tut = models.Resource.all().filter('url =', '/' + relpath).get()

        # If tutorial is marked as draft, redirect and don't show it.
        if tut and tut.draft:
          return self.redirect('/tutorials')

        # Localize title and description.
        if tut:
          if tut.title:
            tut.title = _(tut.title)
          if hasattr(tut, 'subtitle') and tut.subtitle:
            tut.subtitle = _(tut.subtitle)
          if tut.description:
            tut.description = _(tut.description)

        # Gather list of localizations by globbing matching directories, then
        # stripping out the current locale and 'static'. Once we have a list,
        # convert it to a series of dictionaries containing the localization's
        # path and name:
        langs = {
          'de': 'Deutsch',
          'en': 'English',
          'fr': 'Français',
          'es': 'Español',
          'it': 'Italiano',
          'ja': '日本語',
          'ko': '한국어',
          'pt': 'Português (Brasil)',
          'ru': 'Pусский',
          'zh': '中文 (简体)'
        }
        loc_list = []
        for d in glob.glob(os.path.join(dir, '*', 'index.html')):
          loc = os.path.basename(os.path.dirname(d))
          if loc not in [locale, 'static']:
            loc_list.append({'path': '/%s/%s' % (loc, relpath),
                             'lang': langs[loc]})

        data = {
          'css_file': css_file,
          'tut': tut,
          'localizations': loc_list,
          'redirect_from_locale': redirect_from_locale
        }
        return self.render(template_path=os.path.join(dir, locale, filename),
                           data=data, relpath=relpath)

      # If the localized file doesn't exist, and the locale isn't English, look
      # for an english version of the file, and redirect the user there if
      # it's found:
      elif os.path.isfile( os.path.join(dir, 'en', filename)):
        return self.redirect("/en/%s?redirect_from_locale=%s" % (relpath,
                                                                 locale))
    elif os.path.isfile(path):
      #TODO(ericbidelman): Don't need these tutorial/update results for query.

      page_number = int(self.request.get('page', default_value=0)) or None
      template_args = dict()

      if page_number:
        template_args['previous_page'] = page_number - 1
        template_args['next_page'] = page_number + 1

      if relpath[:-1] in ['mobile', 'gaming', 'business']:
        results = TagsHandler().get_as_db(
            relpath[:-1], limit=self.FEATURE_PAGE_WHATS_NEW_LIMIT)
      elif relpath == 'updates':
        results = []
      else:
        include_updates = None
        if relpath == '':
          resource_limit = 9
          include_updates = True
        else:
          resource_limit = None

        if page_number is not None:
          results = models.Resource.get_all(order='-publication_date',
              page=page_number, include_updates=include_updates)
        else:
          results = models.Resource.get_all(order='-publication_date',
              limit=resource_limit, include_updates=include_updates)

      tutorials = [] # List of final result set.
      authors = [] # List of authors related to the result set.
      for r in results:
        resource_type = [x for x in r.tags if x.startswith('type:')]
        if len(resource_type):
          resource_type = resource_type[0].replace('type:', '')

        if r.url.startswith('/'):
          # Localize title and description if article is localized.
          filepath = os.path.join(self.BASEDIR, 'content', r.url[1:], self.locale,
                                  'index.html')
          if os.path.isfile(filepath):
            if r.title:
              r.title = _(r.title)
            if hasattr(r, 'subtitle') and r.subtitle:
              r.subtitle = _(r.subtitle)
            if r.description:
              r.description = _(r.description)
          # Point the article to the localized version, regardless.
          r.url = "/%s%s" % (self.locale, r.url)

        tutorials.append(r)
        tutorials[-1].classes = [x.replace('class:', '') for x in r.tags
                                 if x.startswith('class:')]
        tutorials[-1].tags = [x for x in r.tags
            if not (x.startswith('class:') or x.startswith('type:'))]
        tutorials[-1].type = resource_type

        #TODO(ericbidelman): Probably don't need author for every result query.
        authors.append(r.author)

      # Remove duplicate authors from the list.
      author_dict = {}
      for a in authors:
        author_dict[a.key().name()] = a
      authors = author_dict.values()

      data = {
        'css_file': css_file,
        'tutorials': tutorials,
        'authors': authors,
        'args': template_args
      }

      return self.render(data, template_path=path, relpath=relpath)

    elif os.path.isfile(path[:path.rfind('.')] + '.html'):
      return self.render(data={'css_file': css_file},
                        template_path=path[:path.rfind('.')] + '.html',
                        relpath=relpath)

    elif os.path.isfile(path + '.html'):
      category = relpath.replace('features/', '')
      updates = TagsHandler().get_as_db(
          'class:' + category, limit=self.FEATURE_PAGE_WHATS_NEW_LIMIT)
      for r in updates:
        if r.url.startswith('/'):
          # Localize title if article is localized.
          filepath = os.path.join(self.BASEDIR, 'content', r.url[1:], self.locale,
                                  'index.html')
          if r.url.startswith('/') and os.path.isfile(filepath) and r.title:
            r.title = _(r.title)
          # Point the article to the localized version, regardless.
          r.url = "/%s%s" % (self.locale, r.url)

      data = {
        'css_file': css_file,
        'category': category,
        'updates': updates
      }
      if relpath == 'why':
        if os.path.isfile(os.path.join(path, locale, 'index.html')):
          data['local_content_path'] = os.path.join(relpath, locale, 'index.html')
        else:
          data['local_content_path'] = os.path.join(relpath, 'en', 'index.html')

      return self.render(data=data, template_path=path + '.html', relpath=relpath)

    # If we've reached here, assume 404.
    return self.render(status=404, message='Page Not Found', template_path='404.html')
Exemple #11
0
    def get(self, relpath, post_id=None):
        self._set_cache_param()

        if relpath == "live":
            user = users.get_current_user()

            # Restrict access to this page to admins and whitelisted users.
            if not users.is_current_user_admin() and user.email() not in settings.WHITELISTED_USERS:
                return self.redirect("/")

            entity = models.LiveData.all().get()
            if entity:
                live_form = models.LiveForm(entity.to_dict(), initial={"gdl_page_url": entity.gdl_page_url})
            else:
                live_form = models.LiveForm()

            template_data = {"live_form": live_form}
            return self.render(data=template_data, template_path="database/live.html", relpath=relpath)

        elif relpath == "author":
            # adds a new author information into DataStore.
            sorted_profiles = models.get_sorted_profiles(update_cache=True)
            template_data = {
                "sorted_profiles": sorted_profiles,
                "profile_amount": len(sorted_profiles),
                "author_form": models.AuthorForm(),
            }
            return self.render(data=template_data, template_path="database/author_new.html", relpath=relpath)

        elif relpath == "drop_all":
            if settings.PROD:
                return self.response.out.write("Handler not allowed in production.")
            self._NukeDB()

        elif relpath == "load_tutorials":
            if settings.PROD:
                return self.response.out.write("Handler not allowed in production.")
            self._AddTestResources()

        elif relpath == "load_authors":
            if settings.PROD:
                return self.response.out.write("Handler not allowed in production.")
            self._AddTestAuthors()

        elif relpath == "load_playground_samples":
            if settings.PROD:
                return self.response.out.write("Handler not allowed in production.")
            self._AddTestPlaygroundSamples()

        elif relpath == "load_studio_samples":
            if settings.PROD:
                return self.response.out.write("Handler not allowed in production.")
            self._AddTestStudioSamples()

        elif relpath == "load_all":
            if settings.PROD:
                return self.response.out.write("Handler not allowed in production.")

            # TODO(ericbidelman): Make this async.
            self._AddTestAuthors()
            self._AddTestResources()
            self._AddTestPlaygroundSamples()
            self._AddTestStudioSamples()

        elif relpath == "resource":
            tutorial_form = models.TutorialForm()

            if post_id:  # /database/resource/1234
                post = models.Resource.get_by_id(int(post_id))
                if post:
                    author_id = post.author.key().name()
                    second_author_id = post.second_author and post.second_author.key().name()

                    # Adjust browser support so it renders to the checkboxes correctly.
                    browser_support = [b.capitalize() for b in post.browser_support]
                    for b in browser_support:
                        if len(b) == 2:
                            browser_support[browser_support.index(b)] = b.upper()

                    form_data = post.to_dict()
                    form_data["tags"] = ", ".join(post.tags)
                    form_data["author"] = author_id
                    form_data["second_author"] = second_author_id or author_id
                    form_data["browser_support"] = browser_support

                    tutorial_form = models.TutorialForm(form_data)

            template_data = {
                "tutorial_form": tutorial_form,
                # get_all() not used b/c we don't care about caching on this page.
                "resources": (models.Resource.all().order("-publication_date").fetch(limit=settings.MAX_FETCH_LIMIT)),
                "post_id": post_id and int(post_id) or "",
            }
            return self.render(data=template_data, template_path="database/resource_new.html", relpath=relpath)

        # Catch all to redirect to proper page.
        return self.redirect("/database/resource")
Exemple #12
0
    def get(self, relpath):

        self._set_cache_param()

        # Handle bug redirects before anything else, as it's trivial.
        if relpath == "new-bug":
            return self.redirect("https://github.com/html5rocks/www.html5rocks.com/issues/new")

        # Handle humans before locale, to prevent redirect to /en/
        # (but still ensure it's dynamic, ie we can't just redirect to a static url)
        if relpath == "humans.txt":
            self.response.headers["Content-Type"] = "text/plain"
            sorted_profiles = models.get_sorted_profiles()
            return self.render(
                data={"sorted_profiles": sorted_profiles, "profile_amount": len(sorted_profiles)},
                template_path="content/humans.txt",
                relpath=relpath,
            )

        # Get the locale: if it's "None", redirect to English
        locale = self.get_language()
        if not locale:
            return self.redirect("/en/%s" % relpath, permanent=True)

        # If there is a locale specified but it has no leading slash, redirect
        if not relpath.startswith("%s/" % locale):
            return self.redirect("/%s/" % locale, permanent=True)

        # If we get here, is because the language is specified correctly,
        # so let's activate it
        self.activate_language(locale)

        # Strip off leading `/[en|de|fr|...]/`
        relpath = re.sub("^/?\w{2,3}(?:/)?", "", relpath)

        # Are we looking for a feed?
        is_feed = self.request.path.endswith(".xml")

        logging.info("relpath: " + relpath)
        # Setup handling of redirected article URLs: If a user tries to access an
        # article from a non-supported language, we'll redirect them to the
        # English version (assuming it exists), with a `redirect_from_locale` GET
        # param.
        redirect_from_locale = self.request.get("redirect_from_locale", "")
        if not re.match("[a-zA-Z]{2,3}$", redirect_from_locale):
            redirect_from_locale = False
        else:
            translation.activate(redirect_from_locale)
            redirect_from_locale = {
                "lang": redirect_from_locale,
                "msg": _(
                    "Sorry, this article isn't available in your native "
                    "language; we've redirected you to the English version."
                ),
            }
            translation.activate(locale)

        # Landing page or /tutorials|features|mobile|gaming|business\/?
        if (relpath == "" or relpath[-1] == "/") or (  # Landing page.
            relpath[-1] != "/" and relpath in ["mobile", "tutorials", "features", "gaming", "business"]
        ):
            path = os.path.join("content", relpath, "index.html")
        else:
            path = os.path.join("content", relpath)

        # Render the .html page if it exists. Otherwise, check that the Atom feed
        # the user is requesting has a corresponding .html page that exists.

        if relpath == "profiles" or relpath == "profiles/":
            profiles = models.get_sorted_profiles()
            for p in profiles:
                p["tuts_by_author"] = models.Resource.get_tutorials_by_author(p["id"])
            return self.render(
                data={"sorted_profiles": profiles}, template_path="content/profiles.html", relpath=relpath
            )
        elif (
            re.search("tutorials/.+", relpath)
            or re.search("mobile/.+", relpath)
            or re.search("gaming/.+", relpath)
            or re.search("business/.+", relpath)
            or re.search("tutorials/casestudies/.+", relpath)
        ) and not is_feed:
            # If this is an old-style mobile article or case study, redirect to the
            # new style.
            match = re.search(("(?P<type>mobile|tutorials/casestudies)" "/(?P<slug>[a-z-_0-9]+).html$"), relpath)
            if match:
                logging.info("Redirecting from old-style URL to the new hotness.")
                return self.redirect("/%s/%s/%s/" % (locale, match.group("type"), match.group("slug")))

            # If no trailing / (e.g. /tutorials/blah), redirect to /tutorials/blah/.
            if relpath[-1] != "/" and not relpath.endswith(".html"):
                return self.redirect(self.request.url + "/")

            # Tutorials look like this on the filesystem:
            #
            #   .../tutorials +
            #                 |
            #                 +-- article-slug  +
            #                 |                 |
            #                 |                 +-- en  +
            #                 |                 |       |
            #                 |                 |       +-- index.html
            #                 ...
            #
            # So, to determine if an HTML page exists for the requested language
            # `split` the file's path, add in the locale, and check existence:
            logging.info("Building request for `%s` in locale `%s`", path, locale)
            (dir, filename) = os.path.split(path)
            if os.path.isfile(os.path.join(dir, locale, filename)):
                # Lookup tutorial by its url. Return the first one that matches.
                # get_all() not used because we don't care about caching on individual
                # tut page.
                tut = models.Resource.all().filter("url =", "/" + relpath).get()

                # If tutorial is marked as draft, redirect and don't show it.
                if tut and tut.draft:
                    return self.redirect("/tutorials")

                # Localize title and description.
                if tut:
                    if tut.title:
                        tut.title = _(tut.title)
                    if hasattr(tut, "subtitle") and tut.subtitle:
                        tut.subtitle = _(tut.subtitle)
                    if tut.description:
                        tut.description = _(tut.description)

                # Gather list of localizations by globbing matching directories, then
                # stripping out the current locale and 'static'. Once we have a list,
                # convert it to a series of dictionaries containing the localization's
                # path and name:
                langs = {
                    "de": "Deutsch",
                    "en": "English",
                    "fr": "Français",
                    "es": "Español",
                    "it": "Italiano",
                    "ja": "日本語",
                    "ko": "한국의",
                    "pt": "Português (Brasil)",
                    "ru": "Pусский",
                    "zh": "中文 (简体)",
                }
                loc_list = []
                for d in glob.glob(os.path.join(dir, "*", "index.html")):
                    loc = os.path.basename(os.path.dirname(d))
                    if loc not in [locale, "static"]:
                        loc_list.append({"path": "/%s/%s" % (loc, relpath), "lang": langs[loc]})

                data = {"tut": tut, "localizations": loc_list, "redirect_from_locale": redirect_from_locale}
                return self.render(template_path=os.path.join(dir, locale, filename), data=data, relpath=relpath)

            # If the localized file doesn't exist, and the locale isn't English, look
            # for an english version of the file, and redirect the user there if
            # it's found:
            elif os.path.isfile(os.path.join(dir, "en", filename)):
                return self.redirect("/en/%s?redirect_from_locale=%s" % (relpath, locale))
        elif os.path.isfile(path):
            # TODO(ericbidelman): Don't need these tutorial/update results for query.
            if relpath in ["mobile", "gaming", "business"]:
                results = TagsHandler().get_as_db(relpath, limit=self.FEATURE_PAGE_WHATS_NEW_LIMIT)
            else:
                if relpath == "":
                    resource_limit = 10
                else:
                    resource_limit = None
                results = models.Resource.get_all(order="-publication_date", limit=resource_limit)

            tutorials = []  # List of final result set.
            authors = []  # List of authors related to the result set.
            for r in results:
                resource_type = [x for x in r.tags if x.startswith("type:")]
                if len(resource_type):
                    resource_type = resource_type[0].replace("type:", "")

                if r.url.startswith("/"):
                    # Localize title and description if article is localized.
                    filepath = os.path.join(self.BASEDIR, "content", r.url[1:], self.locale, "index.html")
                    if os.path.isfile(filepath):
                        if r.title:
                            r.title = _(r.title)
                        if hasattr(r, "subtitle") and r.subtitle:
                            r.subtitle = _(r.subtitle)
                        if r.description:
                            r.description = _(r.description)
                    # Point the article to the localized version, regardless.
                    r.url = "/%s%s" % (self.locale, r.url)

                tutorials.append(r)
                tutorials[-1].classes = [x.replace("class:", "") for x in r.tags if x.startswith("class:")]
                tutorials[-1].tags = [x for x in r.tags if not (x.startswith("class:") or x.startswith("type:"))]
                tutorials[-1].type = resource_type

                # TODO(ericbidelman): Probably don't need author for every result query.
                authors.append(r.author)

            # Remove duplicate authors from the list.
            author_dict = {}
            for a in authors:
                author_dict[a.key().name()] = a
            authors = author_dict.values()

            return self.render(data={"tutorials": tutorials, "authors": authors}, template_path=path, relpath=relpath)

        elif os.path.isfile(path[: path.rfind(".")] + ".html"):
            return self.render(data={}, template_path=path[: path.rfind(".")] + ".html", relpath=relpath)

        elif os.path.isfile(path + ".html"):
            category = relpath.replace("features/", "")
            updates = TagsHandler().get_as_db("class:" + category, limit=self.FEATURE_PAGE_WHATS_NEW_LIMIT)
            for r in updates:
                if r.url.startswith("/"):
                    # Localize title if article is localized.
                    filepath = os.path.join(self.BASEDIR, "content", r.url[1:], self.locale, "index.html")
                    if r.url.startswith("/") and os.path.isfile(filepath) and r.title:
                        r.title = _(r.title)
                    # Point the article to the localized version, regardless.
                    r.url = "/%s%s" % (self.locale, r.url)

            data = {"category": category, "updates": updates}
            if relpath == "why":
                if os.path.isfile(os.path.join(path, locale, "index.html")):
                    data["local_content_path"] = os.path.join(relpath, locale, "index.html")
                else:
                    data["local_content_path"] = os.path.join(relpath, "en", "index.html")

            return self.render(data=data, template_path=path + ".html", relpath=relpath)

        # If we've reached here, assume 404.
        return self.render(status=404, message="Page Not Found", template_path="404.html")