Branch: refs/heads/master Author: Enrico Tröger enrico.troeger@uvena.de Committer: Enrico Tröger enrico.troeger@uvena.de Date: Sun, 31 Mar 2019 21:47:58 UTC Commit: 29d0f2933ceb55fedb0804f123f11d1ad008e17f https://github.com/geany/www.geany.org/commit/29d0f2933ceb55fedb0804f123f11d...
Log Message: ----------- PEP8 cleanup
Modified Paths: -------------- geany/apps.py geany/decorators.py geany/hosts.py geany/management/commands/dump_database.py geany/settings.py geany/sitemaps.py geany/templatetags/geany_tags.py geany/urls.py geany/wsgi.py latest_version/admin.py latest_version/context_processors.py latest_version/models.py latest_version/urls.py news/admin.py news/feeds.py news/models.py news/sitemaps.py news/templatetags/news_tags.py news/urls.py news/views.py nightlybuilds/database_routers.py nightlybuilds/models.py nightlybuilds/templatetags/nightlybuilds_tags.py nightlybuilds/urls.py nightlybuilds/views.py pastebin/admin.py pastebin/api/create.py pastebin/forms.py pastebin/highlight.py pastebin/management/commands/cleanup_snippets.py pastebin/management/commands/generate_snippets_css.py pastebin/models.py pastebin/templatetags/pastebin_tags.py pastebin/urls.py pastebin/views.py static_docs/generate_i18n_statistics.py static_docs/github_client.py static_docs/management/commands/generate_i18n_statistics.py static_docs/urls.py static_docs/views.py
Modified: geany/apps.py 1 lines changed, 0 insertions(+), 1 deletions(-) =================================================================== @@ -15,7 +15,6 @@ from django.apps import AppConfig
-######################################################################## class GeanyAppConfig(AppConfig): name = 'geany' verbose_name = "Geany"
Modified: geany/decorators.py 17 lines changed, 10 insertions(+), 7 deletions(-) =================================================================== @@ -5,32 +5,35 @@ # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. -# +# # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
- from binascii import hexlify -from django.core.cache import cache as _djcache import inspect
+from django.core.cache import cache as _djcache +
CACHE_TIMEOUT_24HOURS = 3600 * 24 CACHE_TIMEOUT_1HOUR = 3600
-#---------------------------------------------------------------------- +# ---------------------------------------------------------------------- def cache_function(timeout=900, ignore_arguments=False): """ Cache the result of a function call for the specified number of seconds, using Django's caching mechanism. - Assumes that the function never returns None (as the cache returns None to indicate a miss), and that the function's result only depends on its parameters. - Note that the ordering of parameters is important. e.g. myFunction(x = 1, y = 2), myFunction(y = 2, x = 1), and myFunction(1,2) will each be cached separately. + Assumes that the function never returns None (as the cache returns None to indicate a miss), + and that the function's result only depends on its parameters. + Note that the ordering of parameters is important. e.g. + myFunction(x = 1, y = 2), myFunction(y = 2, x = 1), and myFunction(1,2) + will each be cached separately.
Usage:
Modified: geany/hosts.py 31 lines changed, 22 insertions(+), 9 deletions(-) =================================================================== @@ -3,20 +3,20 @@ # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. -# +# # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
-from django_hosts import patterns, host +from django_hosts import host, patterns from django_hosts.callbacks import cached_host_site
-#---------------------------------------------------------------------- +# ---------------------------------------------------------------------- def cached_host_site_extended(request, *args, **kwargs): # call the original django-hosts callback to do the work cached_host_site(request, *args, **kwargs) @@ -26,14 +26,27 @@ def cached_host_site_extended(request, *args, **kwargs): request.site_id = request.site.id
-host_patterns = patterns('', +host_patterns = patterns( + '', # nightlybuilds (nightly.geany.org and nightly.local.geany.org) - host(r'^nightly(.local|.dev)?.geany.org(:[0-9]*)?$', 'nightlybuilds.urls', name='nightly.geany.org', callback=cached_host_site_extended), - host(r'^geany.nightlybuilds.org(:[0-9]*)?$', 'nightlybuilds.urls', name='geany.nightlybuilds.org', callback=cached_host_site_extended), + host( + r'^nightly(.local|.dev)?.geany.org(:[0-9]*)?$', 'nightlybuilds.urls', + name='nightly.geany.org', + callback=cached_host_site_extended), + host( + r'^geany.nightlybuilds.org(:[0-9]*)?$', 'nightlybuilds.urls', + name='geany.nightlybuilds.org', + callback=cached_host_site_extended),
# pastebin (pastebin.geany.org and pastebin.local.geany.org) - host(r'^pastebin(.local|.dev)?.geany.org(:[0-9]*)?$', 'pastebin.urls', name='pastebin.geany.org', callback=cached_host_site_extended), + host( + r'^pastebin(.local|.dev)?.geany.org(:[0-9]*)?$', 'pastebin.urls', + name='pastebin.geany.org', + callback=cached_host_site_extended),
# default - host(r'^www.geany.org(:[0-9]*)?$', 'geany.urls', name='www.geany.org', callback=cached_host_site_extended), + host( + r'^www.geany.org(:[0-9]*)?$', 'geany.urls', + name='www.geany.org', + callback=cached_host_site_extended), )
Modified: geany/management/commands/dump_database.py 3 lines changed, 1 insertions(+), 2 deletions(-) =================================================================== @@ -15,11 +15,10 @@ from django.core.management import BaseCommand, call_command
-######################################################################## class Command(BaseCommand): help = "Dump the database (excluding users, sessions and logs)"
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def handle(self, *args, **options): call_command( 'dumpdata',
Modified: geany/settings.py 42 lines changed, 26 insertions(+), 16 deletions(-) =================================================================== @@ -13,9 +13,12 @@ # along with this program. If not, see http://www.gnu.org/licenses/.
from __future__ import absolute_import, unicode_literals + import os + from django.utils.translation import ugettext_lazy as _
+ ###################### # MEZZANINE SETTINGS # ###################### @@ -133,6 +136,7 @@ ALLOWED_HOSTS = ('127.0.0.1', 'geany.org', 'www.geany.org') +INTERNAL_IPS = ("127.0.0.1", "10.0.44.3", "37.120.182.205", "2a03:4000:f:40f:99::205")
# Local time zone for this installation. Choices can be found here: @@ -407,8 +411,14 @@ )
ADMIN_MENU_ORDER = ( - (_("Content"), ("pages.Page", "blog.BlogPost", "news.NewsPost", - "generic.ThreadedComment", "mezzanine_blocks.Block", "mezzanine_blocks.RichBlock", (_("Media Library"), "fb_browse"),)), + (_("Content"), ( + "pages.Page", + "blog.BlogPost", + "news.NewsPost", + "generic.ThreadedComment", + "mezzanine_blocks.Block", + "mezzanine_blocks.RichBlock", + (_("Media Library"), "fb_browse"),)), (_("Site"), ( "sites.Site", "redirects.Redirect", @@ -471,9 +481,9 @@ } }, 'handlers': { - 'console':{ - 'level':'DEBUG', - 'class':'logging.StreamHandler', + 'console': { + 'level': 'DEBUG', + 'class': 'logging.StreamHandler', 'formatter': 'verbose' }, 'mail_admins': { @@ -484,22 +494,22 @@ }, 'loggers': { '': { - 'handlers':['console', 'mail_admins'], - 'level':'DEBUG', + 'handlers': ['console', 'mail_admins'], + 'level': 'DEBUG', 'propagate': False, }, 'root': { - 'handlers':['console', 'mail_admins'], - 'level':'DEBUG', + 'handlers': ['console', 'mail_admins'], + 'level': 'DEBUG', 'propagate': False, }, 'py.warnings': { 'propagate': True, - 'level':'DEBUG', + 'level': 'DEBUG', }, 'django': { 'propagate': True, - 'level':'DEBUG', + 'level': 'DEBUG', }, 'django.db': { 'level': 'INFO', @@ -521,7 +531,7 @@ # IGNORE WARNINGS # ################### SILENCED_SYSTEM_CHECKS = ( - 'fields.W162' # warning about longtext index in easy-audit not supported on MySQL + 'fields.W162' # warning about longtext index in easy-audit not supported on MySQL )
@@ -536,15 +546,15 @@ # Instead of doing "from .local_settings import *", we use exec so that # local_settings has full access to everything defined in this module.
-f = os.path.join(PROJECT_APP_PATH, 'local_settings.py') -if os.path.exists(f): +filename = os.path.join(PROJECT_APP_PATH, 'local_settings.py') +if os.path.exists(filename): import sys import imp module_name = '{}.local_settings'.format(PROJECT_APP) module = imp.new_module(module_name) - module.__file__ = f + module.__file__ = filename sys.modules[module_name] = module - exec(open(f, 'rb').read()) + exec(open(filename, 'rb').read())
####################
Modified: geany/sitemaps.py 53 lines changed, 25 insertions(+), 28 deletions(-) =================================================================== @@ -19,6 +19,7 @@ from mezzanine.conf import settings from mezzanine.core.sitemaps import DisplayableSitemap
+ """ Sitemap generation GeanyMainSitemap is the main class which generates sitemap items @@ -35,7 +36,6 @@ """
-######################################################################## class GeanyMainSitemap(DisplayableSitemap): """ Sitemap class for Django's sitemaps framework that returns @@ -44,59 +44,57 @@ class GeanyMainSitemap(DisplayableSitemap): changefreq = 'monthly' priority = 0.5
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def items(self): items = super(GeanyMainSitemap, self).items() additional_app_items = self._get_additional_app_items() items.extend(additional_app_items) return items
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _get_additional_app_items(self): return sitemap_registry.get_all_items()
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def lastmod(self, obj): return getattr(obj, 'publish_date', None)
-######################################################################## class SitemapItem(object): """Simulate a model, mainly to provide get_absolute_url() for Sitemaps"""
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def __init__(self, name, absolute_url, publish_date=None, priority=0.5): self._name = name self._absolute_url = absolute_url self._publish_date = publish_date self._priority = priority
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get_absolute_url(self): return self._absolute_url
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- @property def name(self): return self._name
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- @property def publish_date(self): return self._publish_date
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- @property def priority(self): return self._priority
-######################################################################## class StaticSitemap(sitemaps.Sitemap): """Return the static sitemap items""" priority = 0.5
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def __init__(self, domain, patterns): self._domain = domain self._patterns = patterns @@ -105,82 +103,81 @@ def __init__(self, domain, patterns): self._url_mapping = {} self._get_site_and_host()
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def items(self): return self.get_static_items() + self.get_dynamic_items()
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get_static_items(self): self._initialize() return [SitemapItem(name, url) for name, url in self._url_mapping.items()]
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _initialize(self): for pattern in self._patterns: if getattr(pattern, 'name', None) is not None: url_resolved = self._resolve_url(pattern.name) if url_resolved: self._url_mapping[pattern.name] = url_resolved
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _get_site_and_host(self): self._site = Site.objects.get(domain=self._domain) self._host = get_host(self._domain)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _resolve_url(self, url): try: return reverse(url, urlconf=self._host.urlconf) except NoReverseMatch: return None
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get_dynamic_items(self): return list()
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def changefreq(self, obj): return 'monthly'
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def location(self, obj): return self._url_mapping[obj.name]
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get_urls(self, page=1, site=None, protocol=None): # pass our site to the parent as we know better which site we are on return super(StaticSitemap, self).get_urls(page, self._site, protocol)
-######################################################################## class SitemapRegistry(object):
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def __init__(self): self._sitemap_generators = list() self._static_items = None
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def add(self, generator_class, url_patterns, site_domain=None): if site_domain is None: site_domain = settings.SITE_DOMAIN_WWW sitemap_generator_item = (generator_class, url_patterns, site_domain) self._sitemap_generators.append(sitemap_generator_item)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _update_static_sitemap_items(self, sitemap_generator_class, url_patterns, site_domain): generator = sitemap_generator_class(site_domain, url_patterns) items = generator.get_static_items() self._static_items.extend(items)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get_all_items(self): if self._static_items is None: self._static_items = self._get_static_items() dynamic_items = self._get_dynamic_items() return self._static_items + dynamic_items
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _get_static_items(self): static_items = list() for sitemap_generator_class, url_patterns, site_domain in self._sitemap_generators: @@ -189,7 +186,7 @@ def _get_static_items(self): static_items.extend(items) return static_items
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _get_dynamic_items(self): dynamic_items = list() for sitemap_generator_class, url_patterns, site_domain in self._sitemap_generators:
Modified: geany/templatetags/geany_tags.py 29 lines changed, 15 insertions(+), 14 deletions(-) =================================================================== @@ -12,38 +12,39 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
+import logging + from django import template from django.conf import settings from mezzanine.template import Library -import logging +
register = Library() logger = logging.getLogger(__name__)
-######################################################################## class EvaluateNode(template.Node): - """As found on http://stackoverflow.com/questions/1278042/in-django-is-there-an-easy-way-to...""" + """As found on http://stackoverflow.com/questions/1278042/in-django-is-there-an-easy-way-to...""" # noqa: E501 pylint: disable=line-too-long
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def __init__(self, variable, target_var_name): self._variable = template.Variable(variable) self._target_var_name = target_var_name
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def render(self, context): try: content = self._variable.resolve(context) content_template = template.Template(content) rendered_content = content_template.render(context) context[self._target_var_name] = rendered_content except (template.VariableDoesNotExist, template.TemplateSyntaxError) as e: - return u'Error rendering: %s' % unicode(e) + return 'Error rendering: %s' % unicode(e)
return ''
-#---------------------------------------------------------------------- +# ---------------------------------------------------------------------- @register.tag(name='evaluate') def do_evaluate(parser, token): """ @@ -52,32 +53,32 @@ def do_evaluate(parser, token): try: _, variable, _, target_var_name = token.split_contents() except ValueError: - raise template.TemplateSyntaxError(u'%r tag requires a single argument' % - token.contents.split()[1]) + raise template.TemplateSyntaxError( + '%r tag requires a single argument' % token.contents.split()[1]) return EvaluateNode(variable, target_var_name)
-#---------------------------------------------------------------------- +# ---------------------------------------------------------------------- @register.simple_tag def get_irc_userlist(): user_list = list() try: with open(settings.IRC_USER_LIST_FILE) as file_h: user_list = file_h.readlines() except IOError as e: - logger.error(u'An error occurred reading IRC user list: %s', unicode(e), exc_info=True) + logger.error('An error occurred reading IRC user list: %s', unicode(e), exc_info=True)
# remove newline characters user_list = [username.strip() for username in user_list] return sorted(user_list)
-#---------------------------------------------------------------------- +# ---------------------------------------------------------------------- @register.filter(name='add_css') def add_css(field, css): # read existing CSS classes - css_classes = field.field.widget.attrs.get('class', u'') + css_classes = field.field.widget.attrs.get('class', '') # add new ones - css_classes = u'%s %s' % (css_classes, css) + css_classes = '%s %s' % (css_classes, css) # render the widget return field.as_widget(attrs={'class': css_classes})
Modified: geany/urls.py 4 lines changed, 2 insertions(+), 2 deletions(-) =================================================================== @@ -26,6 +26,7 @@ from geany.sitemaps import GeanyMainSitemap from nightlybuilds.views import NightlyBuildsView
+ sitemaps = {"sitemaps": {"all": GeanyMainSitemap}}
@@ -83,5 +84,4 @@
if settings.DEBUG: urlpatterns += ( - url(r'^media/(?P<path>.*)$', static_serve, {'document_root': settings.MEDIA_ROOT, }), - ) + url(r'^media/(?P<path>.*)$', static_serve, {'document_root': settings.MEDIA_ROOT, }),)
Modified: geany/wsgi.py 6 lines changed, 4 insertions(+), 2 deletions(-) =================================================================== @@ -12,7 +12,9 @@ from django.core.wsgi import get_wsgi_application from mezzanine.utils.conf import real_project_name
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", - "%s.settings" % real_project_name("geany")) + +os.environ.setdefault( + "DJANGO_SETTINGS_MODULE", + "{}.settings".format(real_project_name("geany")))
application = get_wsgi_application()
Modified: latest_version/admin.py 10 lines changed, 5 insertions(+), 5 deletions(-) =================================================================== @@ -3,30 +3,30 @@ # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. -# +# # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
from django.contrib import admin + from latest_version.models import LatestVersion
-######################################################################## class LatestVersionAdmin(admin.ModelAdmin):
model = LatestVersion
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def has_add_permission(self, request): """A fake model should not be added""" return False
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def has_delete_permission(self, request, obj=None): """A fake model should not be added""" return False
Modified: latest_version/context_processors.py 8 lines changed, 4 insertions(+), 4 deletions(-) =================================================================== @@ -3,20 +3,20 @@ # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. -# +# # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
-from latest_version.models import LatestVersion from geany.decorators import cache_function, CACHE_TIMEOUT_1HOUR +from latest_version.models import LatestVersion
-#---------------------------------------------------------------------- +# ---------------------------------------------------------------------- @cache_function(CACHE_TIMEOUT_1HOUR, ignore_arguments=True) def latest_version(request): geany_latest_version = LatestVersion.objects.get(id=1)
Modified: latest_version/models.py 22 lines changed, 11 insertions(+), 11 deletions(-) =================================================================== @@ -15,33 +15,33 @@ from django.db import models
-######################################################################## class LatestVersion(models.Model):
- version = models.CharField(max_length=50, verbose_name=u'Latest Geany version') - github_link = models.CharField(max_length=255, verbose_name=u'Link to the Commits page on Github (everything after https://github.com/geany/geany/)') + version = models.CharField(max_length=50, verbose_name='Latest Geany version') release_date = models.DateTimeField() + github_link = models.CharField( + max_length=255, + verbose_name='Link to the Commits page on Github (everything after ' + 'https://github.com/geany/geany/)')
- - ######################################################################## class Meta: - verbose_name = u'Latest Version' - verbose_name_plural = u'Latest Version' + verbose_name = 'Latest Version' + verbose_name_plural = 'Latest Version'
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def save(self): """Save but replace the existing row instead of adding a new one""" self.id = 1 models.Model.save(self)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def delete(self): """Never delete anything"""
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def __unicode__(self): return str(self)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def __str__(self): return 'Geany {}'.format(self.version)
Modified: latest_version/urls.py 7 lines changed, 2 insertions(+), 5 deletions(-) =================================================================== @@ -14,7 +14,8 @@
from django.conf.urls import url from django.views.generic import TemplateView -from geany.sitemaps import StaticSitemap, sitemap_registry + +from geany.sitemaps import sitemap_registry, StaticSitemap
urlpatterns = ( @@ -25,9 +26,5 @@ name='latest_version'), )
-# Adds ``STATIC_URL`` to the context of error pages, so that error pages can use JS, CSS and images. -handler404 = "mezzanine.core.views.page_not_found" -handler500 = "mezzanine.core.views.server_error" - # register our urlpatterns to the global sitemap generator sitemap_registry.add(StaticSitemap, urlpatterns)
Modified: news/admin.py 7 lines changed, 3 insertions(+), 4 deletions(-) =================================================================== @@ -18,7 +18,6 @@ from news.models import NewsPost
-######################################################################## class NewsPostAdmin(admin.ModelAdmin): list_display = ('title', 'user', 'status', 'publish_date') list_editable = ("status",) @@ -28,14 +27,14 @@ class NewsPostAdmin(admin.ModelAdmin): actions = ['_toggle_many_published'] radio_fields = {"status": admin.HORIZONTAL}
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def save_model(self, request, obj, form, change): if not obj.user_id: # set logged in user as author obj.user = request.user obj.save()
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _toggle_many_published(self, request, queryset): # this is not really as efficient as it could be as the query is performed, but I don't know # a way to get the primary keys in the queryset without executing it @@ -45,7 +44,7 @@ def _toggle_many_published(self, request, queryset): rows_updated += 1 self.message_user(request, "{} News posts were successfully changed.".format(rows_updated))
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _toggle_newspost_published_status(self, newspost): if newspost.status == CONTENT_STATUS_PUBLISHED: newspost.status = CONTENT_STATUS_DRAFT
Modified: news/feeds.py 16 lines changed, 8 insertions(+), 8 deletions(-) =================================================================== @@ -14,42 +14,42 @@
from django.contrib.syndication.views import Feed from django.urls import reverse +from mezzanine.conf import settings from mezzanine.core.templatetags.mezzanine_tags import richtext_filters from mezzanine.utils.html import absolute_urls -from mezzanine.conf import settings + from news.models import NewsPost
-######################################################################## class LatestNewsPostsFeed(Feed):
title = "Geany project news" description = "News feed for the Geany project"
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def link(self): return reverse("news_list")
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def items(self): return NewsPost.objects.recently_published(count=200)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def item_title(self, item): return item.title
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def item_description(self, item): description = richtext_filters(item.content) absolute_urls_name = "mezzanine.utils.html.absolute_urls" if absolute_urls_name not in settings.RICHTEXT_FILTERS: description = absolute_urls(description) return description
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def item_pubdate(self, item): return item.publish_date
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def item_author_name(self, item): return item.user.get_full_name() or item.user.username
Modified: news/models.py 23 lines changed, 10 insertions(+), 13 deletions(-) =================================================================== @@ -23,7 +23,6 @@ from mezzanine.utils.urls import slugify
-######################################################################## class PublishedManager(models.Manager): """ Provides filter for restricting items returned by status and @@ -32,7 +31,7 @@ class PublishedManager(models.Manager): # this is a clone of mezzanine.core.managers.PublishedManager but with the # 'expiry_date' field removed
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def published(self, for_user=None): """ For non-staff users, return items with a published status and @@ -45,16 +44,15 @@ def published(self, for_user=None): models.Q(publish_date__lte=now()) | models.Q(publish_date__isnull=True), models.Q(status=CONTENT_STATUS_PUBLISHED))
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def recently_published(self, count=5, for_user=None): return self.published(for_user).order_by('-publish_date')[:count]
-######################################################################## class NewsPost(models.Model):
slug = models.CharField(_('Slug'), max_length=255, editable=False, db_index=True) - title = models.CharField(_(u'Title'), max_length=255, blank=True) + title = models.CharField(_('Title'), max_length=255, blank=True) content = RichTextField(_('Content')) user = models.ForeignKey( get_user_model_name(), @@ -68,35 +66,34 @@ class NewsPost(models.Model): db_index=True, help_text=_('With Draft chosen, will only be shown for admin users on the site.')) entry_date = models.DateTimeField( - _(u'Published'), + _('Published'), editable=False, auto_now_add=True, db_index=True) publish_date = models.DateTimeField( - _(u'Published on'), + _('Published on'), blank=True, db_index=True, default=timezone.now)
# add a 'published' method to the Manager to filter by published status objects = PublishedManager()
- ######################################################################## class Meta: ordering = ('-publish_date',) - verbose_name = _(u'News') - verbose_name_plural = _(u'News') + verbose_name = _('News') + verbose_name_plural = _('News')
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.title) super(NewsPost, self).save(*args, **kwargs)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get_absolute_url(self): return reverse('news_detail', kwargs={'newspost_slug': self.slug})
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def __unicode__(self): return self.title
Modified: news/sitemaps.py 3 lines changed, 1 insertions(+), 2 deletions(-) =================================================================== @@ -16,10 +16,9 @@ from news.models import NewsPost
-######################################################################## class NewsPostSitemap(StaticSitemap): """Return the static sitemap items + the last five most recent News posts"""
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get_dynamic_items(self): return list(NewsPost.objects.recently_published(count=30))
Modified: news/templatetags/news_tags.py 4 lines changed, 3 insertions(+), 1 deletions(-) =================================================================== @@ -13,12 +13,14 @@ # along with this program. If not, see http://www.gnu.org/licenses/.
from django import template + from news.models import NewsPost
+ register = template.Library()
-#---------------------------------------------------------------------- +# ---------------------------------------------------------------------- @register.inclusion_tag("news/list_embedded.html", takes_context=True) def get_recent_news(context): user = context.request.user
Modified: news/urls.py 3 lines changed, 2 insertions(+), 1 deletions(-) =================================================================== @@ -13,10 +13,11 @@ # along with this program. If not, see http://www.gnu.org/licenses/.
from django.conf.urls import url + from geany.sitemaps import sitemap_registry from news.feeds import LatestNewsPostsFeed from news.sitemaps import NewsPostSitemap -from news.views import NewsListView, NewsDetailView +from news.views import NewsDetailView, NewsListView
urlpatterns = (
Modified: news/views.py 17 lines changed, 7 insertions(+), 10 deletions(-) =================================================================== @@ -13,19 +13,19 @@ # along with this program. If not, see http://www.gnu.org/licenses/.
from django.http import JsonResponse -from django.shortcuts import render, get_object_or_404 +from django.shortcuts import get_object_or_404, render from django.template.defaultfilters import date, safe from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt from django.views.generic import DetailView, ListView, View from mezzanine.core.templatetags.mezzanine_tags import richtext_filters + from news.models import NewsPost
-######################################################################## class NewsPostPublishedMixin(object):
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get_queryset(self): """ filter non-published news posts except for staff users """ user = self.request.user @@ -34,41 +34,38 @@ def get_queryset(self): order_by('-publish_date')
-######################################################################## class NewsListView(NewsPostPublishedMixin, ListView):
model = NewsPost template_name = 'news/list.html'
-######################################################################## class NewsDetailView2(NewsPostPublishedMixin, DetailView):
model = NewsPost template_name = 'news/detail.html'
-######################################################################## class NewsDetailView(NewsPostPublishedMixin, View): template_name = 'news/detail.html'
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- @method_decorator(csrf_exempt) def dispatch(self, *args, **kwargs): return super(NewsDetailView, self).dispatch(*args, **kwargs)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get(self, request, newspost_slug): newspost = get_object_or_404(NewsPost, slug=newspost_slug) return render(request, self.template_name, {'newspost': newspost})
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def post(self, request, *args, **kwargs): newspost_slug = request.POST.get('newspost_slug') try: newspost = NewsPost.objects.get(slug=newspost_slug) except NewsPost.DoesNotExist: - error_message = u'News post item for "{}" could not be found'.format(newspost_slug) + error_message = 'News post item for "{}" could not be found'.format(newspost_slug) result = dict(error=error_message) else: # adapt to dict
Modified: nightlybuilds/database_routers.py 9 lines changed, 4 insertions(+), 5 deletions(-) =================================================================== @@ -13,13 +13,12 @@ # along with this program. If not, see http://www.gnu.org/licenses/.
-######################################################################## class NightlyBuildsRouter(object): """ A router to control all database operations on models in the nightlybuilds application. """ - #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def db_for_read(self, model, **hints): """ Attempts to read auth models go to nightlybuilds. @@ -28,7 +27,7 @@ def db_for_read(self, model, **hints): return 'nightlybuilds' return None
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def db_for_write(self, model, **hints): """ Attempts to write auth models go to nightlybuilds. @@ -37,7 +36,7 @@ def db_for_write(self, model, **hints): return 'nightlybuilds' return None
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def allow_relation(self, obj1, obj2, **hints): """ Allow relations if a model in the auth app is involved. @@ -47,6 +46,6 @@ def allow_relation(self, obj1, obj2, **hints): return True return None
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def allow_migrate(self, db, app_label, model_name=None, **hints): return app_label != 'nightlybuilds'
Modified: nightlybuilds/models.py 18 lines changed, 7 insertions(+), 11 deletions(-) =================================================================== @@ -15,7 +15,6 @@ from django.db import models
-######################################################################## class NightlyBuildTarget(models.Model):
nightly_build_target_id = models.PositiveIntegerField(primary_key=True) @@ -31,17 +30,15 @@ class NightlyBuildTarget(models.Model): blank=True, on_delete=models.PROTECT)
- ######################################################################## class Meta: ordering = ('name', 'arch') db_table = 'nightly_build_target'
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def __unicode__(self): return '%s %s' % (self.name, self.arch)
-######################################################################## class NightlyBuild(models.Model):
nightly_build_id = models.PositiveIntegerField(primary_key=True) @@ -57,22 +54,21 @@ class NightlyBuild(models.Model): build_host = models.CharField(max_length=255) build_date = models.DateTimeField(max_length=255)
- ######################################################################## class Meta: ordering = ('-build_date',) db_table = 'nightly_build'
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get_status(self): return not self.status
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get_status_text(self): if self.get_status(): - return u'Built successfully' - else: - return 'Build failed, see the logs for details' + return 'Built successfully'
- #---------------------------------------------------------------------- + return 'Build failed, see the logs for details' + + # ---------------------------------------------------------------------- def __unicode__(self): return '%s %s' % (self.build_date, self.nightly_build_target)
Modified: nightlybuilds/templatetags/nightlybuilds_tags.py 19 lines changed, 10 insertions(+), 9 deletions(-) =================================================================== @@ -12,20 +12,21 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
+import os + from django import template from django.conf import settings from django.utils.html import format_html -import os
register = template.Library() base_dir = settings.NIGHTLYBUILDS_BASE_DIR
-#---------------------------------------------------------------------- +# ---------------------------------------------------------------------- @register.simple_tag def get_build_log(nightly_build, log_type): - if log_type == u'Stdout': + if log_type == 'Stdout': log = nightly_build.log_stdout else: log = nightly_build.log_stderr @@ -39,20 +40,20 @@ def get_build_log(nightly_build, log_type): else: if size > 0: return format_html( - u'<a href="/{}/{}">{}</stdout>', + '<a href="/{}/{}">{}</stdout>', nightly_build.nightly_build_target.folder, log, log_type) - return u'' + return ''
-#---------------------------------------------------------------------- +# ---------------------------------------------------------------------- @register.simple_tag def get_details(nightly_build): header_txt = os.path.join(base_dir, nightly_build.nightly_build_target.folder, 'HEADER.txt') if os.path.exists(header_txt): return format_html( - u'<a href="/{}/">Details</a>', + '<a href="/{}/">Details</a>', nightly_build.nightly_build_target.folder) - else: - return u'' + + return ''
Modified: nightlybuilds/urls.py 15 lines changed, 2 insertions(+), 13 deletions(-) =================================================================== @@ -12,8 +12,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
-from django.conf import settings -from django.conf.urls import include, url +from django.conf.urls import url + from geany.sitemaps import StaticSitemap from nightlybuilds.views import NightlyBuildsView
@@ -25,20 +25,9 @@ url(r'^$', NightlyBuildsView.as_view(), name='home'), ]
-# Django-Debug-Toolbar support -if settings.DEBUG: - import debug_toolbar - urlpatterns += ( - url(r'^__debug__/', include(debug_toolbar.urls)), - ) - # Sitemap framework sitemaps = {"sitemaps": {"all": StaticSitemap('nightly.geany.org', urlpatterns)}} urlpatterns += ( # use our custom sitemap implementation url(r"^sitemap.xml$", 'django.contrib.sitemaps.views.sitemap', sitemaps), ) - -# Adds ``STATIC_URL`` to the context of error pages, so that error pages can use JS, CSS and images. -handler404 = "mezzanine.core.views.page_not_found" -handler500 = "mezzanine.core.views.server_error"
Modified: nightlybuilds/views.py 2 lines changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -14,10 +14,10 @@
from django.db.models import F from django.views.generic import ListView + from nightlybuilds.models import NightlyBuild
-######################################################################## class NightlyBuildsView(ListView): template_name = "nightlybuilds.html"
Modified: pastebin/admin.py 8 lines changed, 4 insertions(+), 4 deletions(-) =================================================================== @@ -3,25 +3,25 @@ # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. -# +# # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
- from django.contrib import admin + from pastebin.models import Snippet, Spamword
-######################################################################## class SnippetAdmin(admin.ModelAdmin): list_display = ('published', 'expires', 'author', 'title') date_hierarchy = 'published' list_filter = ('published',)
+ admin.site.register(Snippet, SnippetAdmin) admin.site.register(Spamword)
Modified: pastebin/api/create.py 24 lines changed, 13 insertions(+), 11 deletions(-) =================================================================== @@ -13,9 +13,11 @@ # along with this program. If not, see http://www.gnu.org/licenses/.
from datetime import timedelta + from django.utils.timezone import now + from pastebin.forms import SnippetForm -from pastebin.highlight import LEXER_LIST_ALL, LEXER_DEFAULT +from pastebin.highlight import LEXER_DEFAULT, LEXER_LIST_ALL from pastebin.models import Snippet
@@ -66,38 +68,37 @@ }
-######################################################################## class SnippetValidationError(Exception): pass
-######################################################################## class CreateSnippetApiController(object):
valid_fields = ('title', 'content', 'expires', 'author', 'lexer')
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def __init__(self, request): self._request = request self._data = request.POST.copy() self._snippet = None self._snippet_form = None
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def create(self): self._validate_passed_fields() self._validate_against_snippet_form() self._create_snippet() return self._snippet
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _validate_passed_fields(self): provided_fields = set(self._data.keys()) additional_fields = provided_fields.difference(self.valid_fields) if additional_fields: - raise SnippetValidationError(u'Invalid fields provided (%s)' % ','.join(additional_fields)) + raise SnippetValidationError( + 'Invalid fields provided (%s)' % ','.join(additional_fields))
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _validate_against_snippet_form(self): self._preprocess_data()
@@ -107,11 +108,12 @@ def _validate_against_snippet_form(self): snippet_form.fields['lexer'].choices = LEXER_LIST_ALL # validate if not snippet_form.is_valid(): - errors = u'\n'.join([u'%s: %s' % (k, v.as_text()) for k, v in snippet_form.errors.items()]) + errors = '\n'.join( + ['%s: %s' % (k, v.as_text()) for k, v in snippet_form.errors.items()]) raise SnippetValidationError(errors) self._snippet_form = snippet_form
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _preprocess_data(self): # compatibility with SnippetForm self._data['expire_options'] = self._data.get('expires', 3600) @@ -128,7 +130,7 @@ def _preprocess_data(self): # lexers and simply override them with 'text' self._data['lexer'] = LEXER_DEFAULT
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _create_snippet(self): cleaned_data = self._snippet_form.cleaned_data expire_options = int(cleaned_data.get('expire_options', 3600))
Modified: pastebin/forms.py 31 lines changed, 16 insertions(+), 15 deletions(-) =================================================================== @@ -13,51 +13,52 @@ # along with this program. If not, see http://www.gnu.org/licenses/.
from datetime import timedelta + from django import forms from django.utils import timezone from django.utils.translation import ugettext_lazy as _ -from pastebin.highlight import LEXER_LIST, LEXER_DEFAULT + +from pastebin.highlight import LEXER_DEFAULT, LEXER_LIST from pastebin.models import Snippet, Spamword
-#=============================================================================== +# =============================================================================== # Snippet Form and Handling -#=============================================================================== +# ===============================================================================
EXPIRE_CHOICES = ( - (3600, _(u'In one hour')), - (3600 * 24 * 7, _(u'In one week')), - (3600 * 24 * 30, _(u'In one month')), - (3600 * 24 * 30 * 12 * 100, _(u'Save forever')), # 100 years, I call it forever ;) + (3600, _('In one hour')), + (3600 * 24 * 7, _('In one week')), + (3600 * 24 * 30, _('In one month')), + (3600 * 24 * 30 * 12 * 100, _('Save forever')), # 100 years, I call it forever ;) )
EXPIRE_DEFAULT = 3600 * 24 * 30
-######################################################################## class SnippetForm(forms.ModelForm):
lexer = forms.ChoiceField( choices=LEXER_LIST, initial=LEXER_DEFAULT, - label=_(u'Lexer'), + label=_('Lexer'), )
expire_options = forms.ChoiceField( choices=EXPIRE_CHOICES, initial=EXPIRE_DEFAULT, - label=_(u'Expires'), + label=_('Expires'), widget=forms.RadioSelect, )
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def __init__(self, request, *args, **kwargs): forms.ModelForm.__init__(self, *args, **kwargs) self.request = request # set author self.fields['author'].initial = self.request.session.get('author', '')
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def clean_content(self): content = self.cleaned_data.get('content') if content: @@ -66,9 +67,10 @@ def clean_content(self): raise forms.ValidationError('This snippet was identified as SPAM.') return content
- #---------------------------------------------------------------------- - def save(self, parent=None, *args, **kwargs): + # ---------------------------------------------------------------------- + def save(self, *args, **kwargs): # Set parent snippet + parent = kwargs.pop('parent', None) if parent: self.instance.parent = parent
@@ -89,7 +91,6 @@ def save(self, parent=None, *args, **kwargs):
return self.request, self.instance
- ######################################################################## class Meta: model = Snippet fields = (
Modified: pastebin/highlight.py 21 lines changed, 8 insertions(+), 13 deletions(-) =================================================================== @@ -12,14 +12,10 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
- from django.utils.html import escape -from pygments.formatters import HtmlFormatter from pygments import highlight -from pygments.lexers import ( - PythonLexer, - get_all_lexers, - get_lexer_by_name) +from pygments.formatters import HtmlFormatter +from pygments.lexers import get_all_lexers, get_lexer_by_name, PythonLexer
LEXER_LIST_ALL = sorted([(i[1][0], i[0]) for i in get_all_lexers()]) @@ -52,30 +48,29 @@ LEXER_DEFAULT = 'text'
-######################################################################## class NakedHtmlFormatter(HtmlFormatter):
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def wrap(self, source, outfile): return self._wrap_code(source)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _wrap_code(self, source): for j, t in source: yield j, t
-#---------------------------------------------------------------------- +# ---------------------------------------------------------------------- def pygmentize(code_string, lexer_name=LEXER_DEFAULT): try: if lexer_name: lexer = get_lexer_by_name(lexer_name) else: - raise Exception(u'Unknown lexer') - except: + raise Exception('Unknown lexer') + except Exception: lexer = PythonLexer()
try: return highlight(code_string, lexer, NakedHtmlFormatter()) - except: + except Exception: return escape(code_string)
Modified: pastebin/management/commands/cleanup_snippets.py 30 lines changed, 17 insertions(+), 13 deletions(-) =================================================================== @@ -3,38 +3,42 @@ # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. -# +# # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
- -from django.core.management.base import LabelCommand from optparse import make_option -from pastebin.models import Snippet import datetime import sys
+from django.core.management.base import LabelCommand + +from pastebin.models import Snippet +
-######################################################################## class Command(LabelCommand): option_list = LabelCommand.option_list + ( - make_option('--dry-run', '-d', action='store_true', dest='dry_run', + make_option( + '--dry-run', '-d', + action='store_true', + dest='dry_run', help='Don't do anything.'), ) - help = "Purges snippets that are expired" + help = 'Purges snippets that are expired'
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def handle(self, *args, **options): deleteable_snippets = Snippet.objects.filter(expires__lte=datetime.datetime.now()) - sys.stdout.write(u"%s snippets gets deleted:\n" % deleteable_snippets.count()) - for d in deleteable_snippets: - sys.stdout.write(u"- %s (%s)\n" % (d.secret_id, d.expires)) + sys.stdout.write('{} snippets gets deleted:\n'.format(deleteable_snippets.count())) + for deleteable_snippet in deleteable_snippets: + sys.stdout.write( + u'- {} ({})\n'.format(deleteable_snippet.secret_id, deleteable_snippet.expires)) if options.get('dry_run'): - sys.stdout.write(u'Dry run - Doing nothing! *crossingfingers*\n') + sys.stdout.write('Dry run - Doing nothing! *crossingfingers*\n') else: deleteable_snippets.delete()
Modified: pastebin/management/commands/generate_snippets_css.py 3 lines changed, 1 insertions(+), 2 deletions(-) =================================================================== @@ -16,12 +16,11 @@ from pygments.formatters import HtmlFormatter
-######################################################################## class Command(BaseCommand): help = "Regenerate CSS for snippet sxntax highlighting py Pygments" requires_system_checks = False
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def handle(self, *args, **options): with open('pastebin/static/css/pygments.css', 'w') as css_file: # You can change style and the html class here:
Modified: pastebin/models.py 57 lines changed, 28 insertions(+), 29 deletions(-) =================================================================== @@ -13,51 +13,51 @@ # along with this program. If not, see http://www.gnu.org/licenses/.
from datetime import timedelta -from django.urls import reverse +import random +import re +import time + from django.db import models +from django.urls import reverse from django.utils import timezone from django.utils.translation import ugettext_lazy as _ + from pastebin.highlight import LEXER_DEFAULT -import random -import re -import time
t = 'abcdefghijkmnopqrstuvwwxyzABCDEFGHIJKLOMNOPQRSTUVWXYZ1234567890'
-#---------------------------------------------------------------------- +# ---------------------------------------------------------------------- def generate_secret_id(length=5): - return ''.join([random.choice(t) for i in range(length)]) + return ''.join([random.choice(t) for i in range(length)]) # pylint: disable=unused-variable
-######################################################################## class Snippet(models.Model): - secret_id = models.CharField(_(u'Secret ID'), max_length=255, blank=True) - title = models.CharField(_(u'Title'), max_length=120, blank=True) - author = models.CharField(_(u'Author'), max_length=30, blank=True) - content = models.TextField(_(u'Content'), ) - content_highlighted = models.TextField(_(u'Highlighted Content'), blank=True) - lexer = models.CharField(_(u'Lexer'), max_length=30, default=LEXER_DEFAULT) - published = models.DateTimeField(_(u'Published'), blank=True, db_index=True) - expires = models.DateTimeField(_(u'Expires'), blank=True, db_index=True) + secret_id = models.CharField(_('Secret ID'), max_length=255, blank=True) + title = models.CharField(_('Title'), max_length=120, blank=True) + author = models.CharField(_('Author'), max_length=30, blank=True) + content = models.TextField(_('Content'), ) + content_highlighted = models.TextField(_('Highlighted Content'), blank=True) + lexer = models.CharField(_('Lexer'), max_length=30, default=LEXER_DEFAULT) + published = models.DateTimeField(_('Published'), blank=True, db_index=True) + expires = models.DateTimeField(_('Expires'), blank=True, db_index=True) parent = models.ForeignKey( 'self', null=True, blank=True, related_name='children', on_delete=models.PROTECT)
- ######################################################################## class Meta: ordering = ('-published',)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def age(self): age = time.mktime(self.published.timetuple()) return self._readable_delta(age)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _readable_delta(self, from_seconds, until_seconds=None): '''Returns a nice readable delta.
@@ -78,7 +78,7 @@ def _readable_delta(self, from_seconds, until_seconds=None): delta_minutes = delta.seconds // 60 delta_hours = delta_minutes // 60
- ## show a fuzzy but useful approximation of the time delta + # show a fuzzy but useful approximation of the time delta if delta.days: return '%d days ago' % (delta.days) elif delta_hours: @@ -88,15 +88,15 @@ def _readable_delta(self, from_seconds, until_seconds=None): else: return '%d seconds ago' % (delta.seconds)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get_linecount(self): return len(self.content.splitlines())
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def content_splitted(self): return self.content_highlighted.splitlines()
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def save(self, *args, **kwargs): if not self.pk and not self.secret_id: self.secret_id = generate_secret_id() @@ -106,29 +106,28 @@ def save(self, *args, **kwargs): self.content_highlighted = self.content models.Model.save(self, *args, **kwargs)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get_absolute_url(self): return reverse('snippet_details', kwargs={'snippet_id': self.secret_id})
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def __unicode__(self): return '%s' % self.secret_id
-######################################################################## class SpamwordManager(models.Manager):
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get_regex(self): - return re.compile(r'|'.join((i[1] for i in self.values_list())), + return re.compile( + r'|'.join((i[1] for i in self.values_list())), re.MULTILINE)
-######################################################################## class Spamword(models.Model): word = models.CharField(max_length=100) objects = SpamwordManager()
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def __unicode__(self): return self.word
Modified: pastebin/templatetags/pastebin_tags.py 18 lines changed, 10 insertions(+), 8 deletions(-) =================================================================== @@ -15,33 +15,35 @@ from django.template import Library from django.template.defaultfilters import timeuntil from django.utils.timezone import now + from pastebin.highlight import pygmentize
+ NINETY_YEARS_IN_DAYS = 32850 # 90 * 365
-register = Library() +register = Library() # pylint: disable=invalid-name
-#---------------------------------------------------------------------- +# ---------------------------------------------------------------------- @register.filter def in_list(value, arg): return value in arg
-#---------------------------------------------------------------------- +# ---------------------------------------------------------------------- @register.filter def timeuntil_or_forever(snippet_expire): ttl = snippet_expire - now() if ttl.days > NINETY_YEARS_IN_DAYS: # snippet TTL 'forever' is defined as 100 years, so if remaining TTL is more than # (90 * 365) days, we most probably got a snippet with TTL 'forever' - return u'forever' - else: - return timeuntil(snippet_expire) + return 'forever' + + return timeuntil(snippet_expire)
-#---------------------------------------------------------------------- +# ---------------------------------------------------------------------- @register.filter def highlight(snippet, line_count=None): h = pygmentize(snippet.content, snippet.lexer) @@ -52,5 +54,5 @@ def highlight(snippet, line_count=None):
if line_count: lines = lines[:line_count] - lines.append(u'...') + lines.append('...') return lines
Modified: pastebin/urls.py 6 lines changed, 3 insertions(+), 3 deletions(-) =================================================================== @@ -12,7 +12,6 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
-from django.conf import settings from django.conf.urls import url from django.views.decorators.cache import never_cache from django.views.generic.base import TemplateView @@ -24,10 +23,11 @@ SnippetDeleteView, SnippetDetailRawView, SnippetDetailView, - SnippetNewView) + SnippetNewView, +)
-urlpatterns = ( +urlpatterns = ( # pylint: disable=invalid-name url(r'^help/$', TemplateView.as_view(template_name='pastebin/help.html'), name='snippet_help'), url(r'^help/api/$', TemplateView.as_view(template_name='pastebin/api.html'), name='snippet_help_api'),
Modified: pastebin/views.py 60 lines changed, 27 insertions(+), 33 deletions(-) =================================================================== @@ -17,7 +17,6 @@ from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseRedirect from django.shortcuts import get_object_or_404, render -from django.template.context import RequestContext from django.template.response import TemplateResponse from django.urls import reverse from django.utils import timezone @@ -32,7 +31,7 @@ from pastebin.models import Snippet
-#---------------------------------------------------------------------- +# ---------------------------------------------------------------------- def _get_snippet_list(no_content=False): try: max_snippets = getattr(settings, 'MAX_SNIPPETS_PER_USER', 10) @@ -48,27 +47,26 @@ def _get_snippet_list(no_content=False): return snippet_list_
-######################################################################## class SnippetNewView(View): template_name = 'pastebin/snippet_new.html'
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- @method_decorator(check_honeypot) def dispatch(self, *args, **kwargs): return super(SnippetNewView, self).dispatch(*args, **kwargs)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get(self, request): snippet_form = SnippetForm(request=request) return self._render_response(request, snippet_form)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _render_response(self, request, snippet_form): snippet_list = _get_snippet_list(no_content=True) template_context = dict(snippet_form=snippet_form, snippet_list=snippet_list) return render(request, self.template_name, template_context)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def post(self, request): snippet_form = SnippetForm(data=request.POST, request=request) if snippet_form.is_valid(): @@ -78,21 +76,19 @@ def post(self, request): return self._render_response(request, snippet_form)
-######################################################################## class SnippetNotFoundError(Exception): pass
-######################################################################## class SnippetDetailView(View): template_name = 'pastebin/snippet_details.html'
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- @method_decorator(check_honeypot) def dispatch(self, *args, **kwargs): return super(SnippetDetailView, self).dispatch(*args, **kwargs)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get(self, request, snippet_id): # housekeeping self._clean_expired_snippets() @@ -117,40 +113,40 @@ def get(self, request, snippet_id):
return render(request, self.template_name, template_context)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _clean_expired_snippets(self): deleteable_snippets = Snippet.objects.filter(expires__lte=timezone.now()) if deleteable_snippets: deleteable_snippets.delete()
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _fetch_snippet(self, snippet_id): try: snippet = Snippet.objects.get(secret_id=snippet_id) except MultipleObjectsReturned: - raise SnippetNotFoundError(_(u'Multiple snippets exist for this slug. This should never happen.')) + raise SnippetNotFoundError( + _('Multiple snippets exist for this slug. This should never happen.')) except ObjectDoesNotExist: - raise SnippetNotFoundError(_(u'This snippet does not exist anymore. Probably its lifetime is expired.')) + raise SnippetNotFoundError( + _('This snippet does not exist anymore. Probably its lifetime is expired.')) else: return snippet
-######################################################################## class SnippetDetailRawView(SnippetDetailView): template_name = 'pastebin/snippet_details_raw.html'
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get(self, request, snippet_id): response = super(SnippetDetailRawView, self).get(request, snippet_id) # set content type response['Content-Type'] = 'text/plain;charset=UTF-8' return response
-######################################################################## class SnippetDeleteView(View):
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get(self, request, snippet_id): snippet = get_object_or_404(Snippet, secret_id=snippet_id) try: @@ -160,25 +156,24 @@ def get(self, request, snippet_id): return TemplateResponse( request, 'errors/403.html', - context=dict(message=_(u'You have no recent snippet list, cookie error?')), + context=dict(message=_('You have no recent snippet list, cookie error?')), status=403) - if not snippet.pk in snippet_list_: + if snippet.pk not in snippet_list_: # 403 response with custom message return TemplateResponse( request, 'errors/403.html', - context=dict(message=_(u'That is not your snippet!')), + context=dict(message=_('That is not your snippet!')), status=403)
snippet.delete() return HttpResponseRedirect(reverse('snippet_new'))
-######################################################################## class LatestSnippetsView(TemplateView): template_name = 'pastebin/snippet_list.html'
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get_context_data(self, **kwargs): snippet_list_ = _get_snippet_list()
@@ -188,30 +183,29 @@ def get_context_data(self, **kwargs): return context
-######################################################################## class SnippetAPIView(View):
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- @method_decorator(csrf_exempt) def dispatch(self, *args, **kwargs): return super(SnippetAPIView, self).dispatch(*args, **kwargs)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def post(self, request): try: controller = CreateSnippetApiController(request) snippet = controller.create() except SnippetValidationError as e: - return HttpResponseBadRequest(unicode(e), content_type=u'text/plain') + return HttpResponseBadRequest(unicode(e), content_type='text/plain')
site = self._get_site(request) absolute_url = snippet.get_absolute_url() - result = u'https://%s%s/' % (site.domain, absolute_url) - return HttpResponse(result, content_type=u'text/plain') + result = 'https://%s%s/' % (site.domain, absolute_url) + return HttpResponse(result, content_type='text/plain')
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _get_site(self, request): if hasattr(request, 'site'): return request.site - else: - return Site.objects.get_current() + + return Site.objects.get_current()
Modified: static_docs/generate_i18n_statistics.py 7 lines changed, 6 insertions(+), 1 deletions(-) =================================================================== @@ -184,7 +184,12 @@ def _update_message_catalog(self): destination_filename = join(self._destination_path, self._message_catalog.filename) pot_file = self._factor_pot_filename()
- update_command = ['msgmerge', source_filename, pot_file, '--output-file', destination_filename] + update_command = [ + 'msgmerge', + source_filename, + pot_file, + '--output-file', + destination_filename] self._execute_command(update_command)
# ----------------------------------------------------------------------
Modified: static_docs/github_client.py 11 lines changed, 6 insertions(+), 5 deletions(-) =================================================================== @@ -15,6 +15,7 @@ # try to get any json implementation from base64 import standard_b64decode import logging + import requests
@@ -26,11 +27,10 @@ logger = logging.getLogger(__name__)
-######################################################################## class GitHubApiClient(object): """"""
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get_file_contents(self, filename): url_parameters = dict(user=GITHUB_USER, repository=GITHUB_REPOSITORY, @@ -44,16 +44,17 @@ def get_file_contents(self, filename): # parse response return self._parse_fetch_file_response(response_json)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _log_rate_limit(self, response): rate_limit_remaining = response.headers['X-RateLimit-Remaining'] rate_limit = response.headers['X-RateLimit-Limit'] logger.info('Github rate limits: %s/%s', rate_limit_remaining, rate_limit)
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _parse_fetch_file_response(self, response_json): + content = response_json['content'] if response_json['encoding'] == 'base64': # standard_b64decode returns a byte string but we want a unicode string - content_utf8 = standard_b64decode(response_json['content']) + content_utf8 = standard_b64decode(content) return content_utf8.decode('utf-8') return content
Modified: static_docs/management/commands/generate_i18n_statistics.py 1 lines changed, 0 insertions(+), 1 deletions(-) =================================================================== @@ -18,7 +18,6 @@ from static_docs.generate_i18n_statistics import TranslationStatisticsGenerator
-######################################################################## class Command(BaseCommand): help = "Generate a JSON file with I18N statistics after updating PO files"
Modified: static_docs/urls.py 5 lines changed, 1 insertions(+), 4 deletions(-) =================================================================== @@ -13,6 +13,7 @@ # along with this program. If not, see http://www.gnu.org/licenses/.
from django.conf.urls import url + from static_docs.views import I18NStatisticsView, ReleaseNotesView, ToDoView
@@ -30,7 +31,3 @@ I18NStatisticsView.as_view(), name='translation_statistics'), ) - -# Adds ``STATIC_URL`` to the context of error pages, so that error pages can use JS, CSS and images. -handler404 = "mezzanine.core.views.page_not_found" -handler500 = "mezzanine.core.views.server_error"
Modified: static_docs/views.py 45 lines changed, 20 insertions(+), 25 deletions(-) =================================================================== @@ -22,55 +22,52 @@ from django.http import Http404 from django.views.generic.base import TemplateView
-from static_docs.github_client import GitHubApiClient from geany.decorators import cache_function, CACHE_TIMEOUT_1HOUR, CACHE_TIMEOUT_24HOURS +from static_docs.github_client import GitHubApiClient
RELEASE_REGEXP = re.compile(r'^Geany (?P<version>[0-9.]+) ((?P<date>.*))$') -DATE_PATTERNS_TO_BE_IGNORED = (u'TBD', u'TBA', u'unreleased') +DATE_PATTERNS_TO_BE_IGNORED = ('TBD', 'TBA', 'unreleased')
logger = logging.getLogger(__name__)
-######################################################################## class ReleaseDto(object): """Simple data holder"""
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def __init__(self): self.version = None self.release_date = None self.release_notes = None
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def __repr__(self): - return u'Geany %s (%s)' % (self.version, self.release_date) + return 'Geany %s (%s)' % (self.version, self.release_date)
-######################################################################## class StaticDocsView(TemplateView): """"""
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def __init__(self, *args, **kwargs): super(StaticDocsView, self).__init__(*args, **kwargs) self._file_contents = None
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _fetch_file_via_github_api(self, filename): client = GitHubApiClient() self._file_contents = client.get_file_contents(filename)
-######################################################################## class ReleaseNotesView(StaticDocsView): """ Grab the NEWS file from GIT master via Github API, parse it and send it back to the template """
- template_name = "pages/documentation/releasenotes.html" + template_name = 'pages/documentation/releasenotes.html'
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get_context_data(self, version=None, **kwargs): releases = self._get_release_notes() release = None @@ -93,27 +90,27 @@ def get_context_data(self, version=None, **kwargs): context['releases'] = releases return context
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- @cache_function(CACHE_TIMEOUT_24HOURS) def _get_release_notes(self): self._fetch_file_via_github_api('NEWS') return self._parse_news_file()
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _parse_news_file(self): releases = list() current_release = None current_release_notes = None for line in self._file_contents.splitlines(): - if line.startswith(u'Geany'): + if line.startswith('Geany'): version, date = self._parse_release_line(line) if not version or date in DATE_PATTERNS_TO_BE_IGNORED: # mark for later exclusion version, date = (None, None) # if we have a previous release already processed, # compress the list of lines to a string if current_release is not None: - current_release.release_notes = u'\n'.join(current_release_notes) + current_release.release_notes = '\n'.join(current_release_notes) # make a new release current_release = ReleaseDto() current_release.version = version @@ -127,48 +124,46 @@ def _parse_news_file(self): releases = [release for release in releases if release.version is not None] return releases
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _parse_release_line(self, line): match = RELEASE_REGEXP.match(line) if match: return match.group('version'), match.group('date') else: - logger.warn(u'Failed parsing NEWS file: release line "%s" invalid', line) + logger.warn('Failed parsing NEWS file: release line "%s" invalid', line) return None, None
-######################################################################## class ToDoView(StaticDocsView): """ Grab the TODO file from GIT master via Github API, parse it and send it back to the template """
template_name = "pages/documentation/todo.html"
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get_context_data(self, **kwargs): todo = self._get_todo() context = super(ToDoView, self).get_context_data(**kwargs) context['todo'] = todo return context
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- @cache_function(CACHE_TIMEOUT_24HOURS) def _get_todo(self): self._fetch_file_via_github_api('TODO') return self._parse_news_file()
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def _parse_news_file(self): return self._file_contents
-######################################################################## class I18NStatisticsView(TemplateView):
template_name = "pages/i18n.html"
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- def get_context_data(self, **kwargs): i18n_statistics = self._get_i18n_statistics() context = super(I18NStatisticsView, self).get_context_data(**kwargs) @@ -178,7 +173,7 @@ def get_context_data(self, **kwargs): context['static_docs_geany_destination_url'] = settings.STATIC_DOCS_GEANY_DESTINATION_URL return context
- #---------------------------------------------------------------------- + # ---------------------------------------------------------------------- @cache_function(CACHE_TIMEOUT_1HOUR) def _get_i18n_statistics(self): filename = os.path.join(
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).