From 5099ae7055b313d1a93d53069c2cfbb0ca0dcf5a Mon Sep 17 00:00:00 2001 From: Gareth Coles Date: Sun, 4 Mar 2018 16:33:01 +0000 Subject: Info pages #13xan #13xak (#36) * Info pages and templates * Info pages and templates * Info pages and templates * Update navigation and fix up HTML * Navigation HTML spacing for readability * Fix error views not using `self.render()` * `render()` method should accept Any for context values * Change header linking CSS to a dedicated class * Rules page * Basic resources page setup * Fix headers for new CSS class * Resource categories and initial resource data * Add link to JSON file on GH - won't work until the branch is merged * Remove info overview page and redirect info root url to resources * Flake8 * Add some tests * Line lengths --- app_test.py | 21 ++++++ pysite/base_route.py | 4 +- pysite/views/error_handlers/http_4xx.py | 24 ++++--- pysite/views/error_handlers/http_5xx.py | 39 +++++------ pysite/views/main/info/index.py | 12 ++++ pysite/views/main/info/resources.py | 21 ++++++ pysite/views/main/info/rules.py | 10 +++ static/resources.json | 45 +++++++++++++ static/style.css | 8 ++- templates/main/info/help.html | 10 +-- templates/main/info/resources.html | 56 +++++++++++++++ templates/main/info/rules.html | 116 ++++++++++++++++++++++++++++++++ templates/main/navigation.html | 42 ++++++++---- 13 files changed, 351 insertions(+), 57 deletions(-) create mode 100644 pysite/views/main/info/index.py create mode 100644 pysite/views/main/info/resources.py create mode 100644 pysite/views/main/info/rules.py create mode 100644 static/resources.json create mode 100644 templates/main/info/resources.html create mode 100644 templates/main/info/rules.html diff --git a/app_test.py b/app_test.py index 2e8a53fb..39c61ff5 100644 --- a/app_test.py +++ b/app_test.py @@ -33,11 +33,32 @@ class BaseEndpoints(SiteTest): response = self.client.get('/', 'http://pytest.local') self.assertEqual(response.status_code, 200) + def test_info_index(self): + """ Check the info index path responds with a 301 """ + response = self.client.get('/info') + self.assertEqual(response.status_code, 301) + def test_info_help(self): """ Check the info help path responds with 200 OK """ response = self.client.get('/info/help') self.assertEqual(response.status_code, 200) + def test_info_resources(self): + """ Check the info resources path responds with 200 OK """ + response = self.client.get('/info/resources') + self.assertEqual(response.status_code, 200) + + def test_info_resources_json(self): + """ Check the resources JSON loads correctly """ + response = self.client.get('/static/resources.json') + self.assertEqual(response.status_code, 200) + self.assertIsInstance(json.loads(response.data), dict) + + def test_info_rules(self): + """ Check the info rules path responds with 200 OK """ + response = self.client.get('/info/help') + self.assertEqual(response.status_code, 200) + def test_not_found(self): """ Check paths without handlers returns 404 Not Found """ response = self.client.get('/nonexistentpath') diff --git a/pysite/base_route.py b/pysite/base_route.py index 400a4649..f389b56e 100644 --- a/pysite/base_route.py +++ b/pysite/base_route.py @@ -1,6 +1,6 @@ # coding=utf-8 from collections import Iterable -from typing import Any, Dict +from typing import Any from flask import Blueprint, Response, jsonify, render_template from flask.views import MethodView @@ -17,7 +17,7 @@ class BaseView(MethodView): name = None # type: str - def render(self, *template_names: str, **context: Dict[str, Any]) -> str: + def render(self, *template_names: str, **context: Any) -> str: """ Render some templates and get them back in a form that you can simply return from your view function. diff --git a/pysite/views/error_handlers/http_4xx.py b/pysite/views/error_handlers/http_4xx.py index 5717feae..74d43d6c 100644 --- a/pysite/views/error_handlers/http_4xx.py +++ b/pysite/views/error_handlers/http_4xx.py @@ -1,5 +1,5 @@ # coding=utf-8 -from flask import render_template, request +from flask import request from werkzeug.exceptions import HTTPException from pysite.base_route import ErrorView @@ -13,17 +13,19 @@ class Error400View(ErrorView): def get(self, error: HTTPException): error_desc = ERROR_DESCRIPTIONS.get(error.code, "We're not really sure what happened there, please try again.") - return render_template("errors/error.html", code=error.code, req=request, error_title=error_desc, - error_message=error_desc + - " If you believe we have made a mistake, please " - "open an issue on our GitHub."), error.code + return self.render( + "errors/error.html", code=error.code, req=request, error_title=error_desc, + error_message=error_desc + + " If you believe we have made a mistake, please " + "open an issue on our GitHub." + ), error.code def post(self, error: HTTPException): error_desc = ERROR_DESCRIPTIONS.get(error.code, "We're not really sure what happened there, please try again.") - return render_template("errors/error.html", code=error.code, req=request, error_title=error_desc, - error_message=error_desc + - " If you believe we have made a mistake, please " - "open an issue on our GitHub."), error.code + return self.render( + "errors/error.html", code=error.code, req=request, error_title=error_desc, + error_message=error_desc + + " If you believe we have made a mistake, please " + "open an issue on our GitHub." + ), error.code diff --git a/pysite/views/error_handlers/http_5xx.py b/pysite/views/error_handlers/http_5xx.py index 6bbc8275..60d3b1bb 100644 --- a/pysite/views/error_handlers/http_5xx.py +++ b/pysite/views/error_handlers/http_5xx.py @@ -1,5 +1,5 @@ # coding=utf-8 -from flask import render_template, request +from flask import request from werkzeug.exceptions import HTTPException from pysite.base_route import ErrorView @@ -13,28 +13,21 @@ class Error500View(ErrorView): def get(self, error: HTTPException): error_desc = ERROR_DESCRIPTIONS.get(error.code, "We're not really sure what happened there, please try again.") - return render_template("errors/error.html", code=error.code, req=request, error_title=error_desc, - error_message="An error occurred while " - "processing this " - "request, please try " - "again later. " - "If you believe we have made a mistake, " - "please " - "file an issue on our GitHub" - "."), error.code + return self.render( + "errors/error.html", code=error.code, req=request, error_title=error_desc, + error_message="An error occurred while processing this request, please try " + "again later. If you believe we have made a mistake, please " + "file an issue on our" + " GitHub." + ), error.code def post(self, error: HTTPException): - error_desc = ERROR_DESCRIPTIONS.get(error.code, - "We're not really sure what happened there, please try again.") + error_desc = ERROR_DESCRIPTIONS.get(error.code, "We're not really sure what happened there, please try again.") - return render_template("errors/error.html", code=error.code, req=request, error_title=error_desc, - error_message="An error occurred while " - "processing this " - "request, please try " - "again later. " - "If you believe we have made a mistake, " - "please " - "file an issue on our GitHub" - "."), error.code + return self.render( + "errors/error.html", code=error.code, req=request, error_title=error_desc, + error_message="An error occurred while processing this request, please try " + "again later. If you believe we have made a mistake, please " + "file an issue on our" + " GitHub." + ), error.code diff --git a/pysite/views/main/info/index.py b/pysite/views/main/info/index.py new file mode 100644 index 00000000..371a5353 --- /dev/null +++ b/pysite/views/main/info/index.py @@ -0,0 +1,12 @@ +# coding=utf-8 +from flask import redirect + +from pysite.base_route import RouteView + + +class IndexView(RouteView): + path = "/info/" + name = "info" + + def get(self): + return redirect("/info/resources") diff --git a/pysite/views/main/info/resources.py b/pysite/views/main/info/resources.py new file mode 100644 index 00000000..bce162f4 --- /dev/null +++ b/pysite/views/main/info/resources.py @@ -0,0 +1,21 @@ +# coding=utf-8 +import json +from logging import getLogger + +from pysite.base_route import RouteView + + +try: + with open("static/resources.json") as fh: + categories = json.load(fh) +except Exception: + getLogger("Resources").exception("Failed to load resources.json") + categories = None + + +class ResourcesView(RouteView): + path = "/info/resources" + name = "info/resources" + + def get(self): + return self.render("main/info/resources.html", categories=categories) diff --git a/pysite/views/main/info/rules.py b/pysite/views/main/info/rules.py new file mode 100644 index 00000000..75faded1 --- /dev/null +++ b/pysite/views/main/info/rules.py @@ -0,0 +1,10 @@ +# coding=utf-8 +from pysite.base_route import RouteView + + +class RulesView(RouteView): + path = "/info/rules" + name = "info/rules" + + def get(self): + return self.render("main/info/rules.html") diff --git a/static/resources.json b/static/resources.json new file mode 100644 index 00000000..1e6bc503 --- /dev/null +++ b/static/resources.json @@ -0,0 +1,45 @@ +{ + "Learning Resources": { + "description": "Tutorials and references for those that are just getting started with python", + "resources": { + "Automate the Boring Stuff with Python": { + "description": "One of the best books out there for Python beginners. You can buy a copy, but there's also a free online version.", + "url": "https://automatetheboringstuff.com/" + }, + "Getting Started for Non-Programmers": { + "description": "The list of resources for non-programmers from Python's official beginners' guide", + "url": "https://wiki.python.org/moin/BeginnersGuide/NonProgrammers" + }, + "Getting Started for Programmers": { + "description": "The list of resources for programmers from Python's official beginners' guide", + "url": "https://wiki.python.org/moin/BeginnersGuide/Programmers" + } + } + }, + "Editors": { + "description": "Lightweight code editors supporting Python", + "resources": { + "Visual Studio Code (Free)": { + "description": "A fully-featured editor based on Electron, extendable with plugins.", + "url": "https://code.visualstudio.com/" + }, + "Sublime Text (Paid, with shareware-style \"trial\")": { + "description": "A powerful Python-backed editor with great community support and a wealth of extensions.", + "url": "https://www.sublimetext.com/" + } + } + }, + "IDEs": { + "description": "Fully-integrated development environments for serious Python work", + "resources": { + "PyCharm (Community and Professional editions available)": { + "description": "The very best Python IDE, with a wealth of advanced features and convenience functions.", + "url": "https://www.jetbrains.com/pycharm/" + }, + "Spyder (Free)": { + "description": "The Scientific PYthon Development EnviRonment. Simpler and lighter than PyCharm, but still packs a punch.", + "url": "https://pythonhosted.org/spyder/" + } + } + } +} diff --git a/static/style.css b/static/style.css index fbbec5c1..2b14c8ce 100644 --- a/static/style.css +++ b/static/style.css @@ -25,7 +25,7 @@ top: 45px !important; } -.uk-article-title a { +.hover-title a { visibility: hidden; opacity: 0; @@ -34,7 +34,7 @@ -webkit-transition: opacity 200ms ease-in-out; } -.uk-article-title:hover a { +.hover-title:hover a { visibility: visible; opacity: 1; @@ -54,4 +54,8 @@ .uk-section { padding-top: 20px; padding-bottom: 30px; +} + +.uk-heading-divider .uk-article-meta { + margin-bottom: 0; } \ No newline at end of file diff --git a/templates/main/info/help.html b/templates/main/info/help.html index d3084f8b..de041f66 100644 --- a/templates/main/info/help.html +++ b/templates/main/info/help.html @@ -4,7 +4,7 @@
-

+

Getting Help @@ -26,7 +26,7 @@ behind that essay are in no way affiliated with us - please do not bother them with your Python problems.

-

+

Before You Ask @@ -110,7 +110,7 @@ whether someone else has asked your question recently, or just feel free to pick one of the help channels and ask your question.

-

+

A Good Question @@ -297,7 +297,7 @@
-

+

Interpreting Answers @@ -364,7 +364,7 @@ people applying actively them, visibly, in public.

-

+

What Not To Ask diff --git a/templates/main/info/resources.html b/templates/main/info/resources.html new file mode 100644 index 00000000..576d68ec --- /dev/null +++ b/templates/main/info/resources.html @@ -0,0 +1,56 @@ +{% extends "main/base.html" %} +{% block title %}Resources{% endblock %} +{% block content %} +
+
+
+

+ Resources + + + + +

+ +

+ This page is intended to be a listing of useful resources for beginner and experienced Python + programmers alike. This page is generated from a JSON file + on GitHub - + if there's a great resource that you love and you don't see it on this page, feel free to submit a + pull request! +

+ + {% if categories is none %} +
+

+ We were unable to load the resources.json file. If you see this, please + notify us! +

+
+ {% else %} + {% for category_name, category_data in categories.items() %} +

+ {{ category_name }} + + + + +
+ +

+ {% for item, data in category_data.resources.items() %} +

+ {{ item }}  
+ {{ data.description }} +

+ {% endfor %} + {% endfor %} + {% endif %} +
+
+
+{% endblock %} \ No newline at end of file diff --git a/templates/main/info/rules.html b/templates/main/info/rules.html new file mode 100644 index 00000000..1853f090 --- /dev/null +++ b/templates/main/info/rules.html @@ -0,0 +1,116 @@ +{% extends "main/base.html" %} +{% block title %}Rules{% endblock %} +{% block content %} +
+
+
+

+ Rules + + + + +

+ +

+ We have a small but strict set of rules on our server. Please read over them and take them on board - + if you don't understand anything or need some clarification, feel free to ask any staff member! +

+
    +
  1. + Be polite, and do not spam +
  2. +
  3. + Follow the Discord community guidelines +
  4. +
  5. + Be patient both with users asking questions, and the users answering them +
  6. +
  7. + Listen to and respect the staff members - we're here to help, but we're all human beings +
  8. +
  9. + All discussion should be kept within the relevant channels for the subject. +
      +
    • + General Python help and support requests go to one of the three help channels - pick + the one that is the quietest at the time. +
    • +
    • + The topical channels can be used for help and support requests, but general discussion + about the subjects covered by them should go there also. +
    • +
    • + If you're working with one of the bots, we ask you to specifically do that in + #bot-commands, to keep the other channels clear of bot output. +
    • +
    • + If you're working on a Python project or something directly related to our server, feel + free to post a link to it in #show-your-projects. We prefer links to source + code over websites, but we'll also accept screenshots and videos if you're not yet ready + to release the code. +
        +
      • + If you or someone else posts a project to #show-your-projects, you may + discuss it in #show-your-projects-discussion. #show-your-projects + is intended to be a listing channel, and any discussion there is removed regularly. +
      • +
      • + Please note, we do not allow postings for communities (such as + forums or other Discord servers) or commercial projects. +
      • +
      +
    • +
    +
  10. +
  11. + This is an English-speaking server. Please speak English to the best of your ability. Google + translate is fine if you're not sure. +
  12. +
  13. + Keep all discussions SFW - No ecchi + or NSFW media. If you wouldn't want + the entire world to know about your interest in it, it doesn't belong on this server. +
  14. +
  15. + We do not allow advertisements for communities or commercial projects - Contact us directly if + you want to discuss a partnership! +
  16. +
+ +

+ Infractions + + + + +

+ +

+ We have a generally no-nonsense policy when it comes to our rules. If you notice someone breaking + them, feel free to mention or DM a staff member and we'll try to deal with it as soon as possible. +

+

+ The possible actions we take based on infractions can include the following: +

+
    +
  • A public verbal/textual warning
  • +
  • A short temporary mute
  • +
  • A long temporary mute
  • +
  • A kick from the server
  • +
  • A temporary ban from the server
  • +
  • A permanent ban from the server
  • +
+

+ While we do discuss more serious matters internally before handing out a punishment, simpler + infractions are dealt with directly by individual staffers and the punishment they hand out is left + to their own decision-making. +

+
+
+
+{% endblock %} \ No newline at end of file diff --git a/templates/main/navigation.html b/templates/main/navigation.html index 5b518822..3178895e 100644 --- a/templates/main/navigation.html +++ b/templates/main/navigation.html @@ -11,40 +11,54 @@

-
-
-- cgit v1.2.3