From 5931919ef35d341eec52206a0f9213d6bcff8349 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 5 Jan 2013 14:34:27 +0100 Subject: [PATCH 001/266] use request.scheme for the flattr js too --- ddportfolioservice/templates/base.mako | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddportfolioservice/templates/base.mako b/ddportfolioservice/templates/base.mako index f6ffba4..648c8f4 100644 --- a/ddportfolioservice/templates/base.mako +++ b/ddportfolioservice/templates/base.mako @@ -37,7 +37,7 @@ License along with this program. If not, see var flattr_url = '${request.scheme}://portfolio.debian.net/'; var flattr_btn='compact'; -

+

${self.body()} From 94cc50e05f33238b59ca15248f9b7865ef0b096e Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 5 Jan 2013 14:35:07 +0100 Subject: [PATCH 002/266] bump version to 0.2.13 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 7997c88..48fde7b 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ except ImportError: setup( name='ddportfolioservice', - version='0.2.12', + version='0.2.13', description='service to create DDPortfolio URLs', long_description="""This is a service implementation that returns a set of personalized URLs as outlined in From 1dee0727f0b42151bbac378d2cc4cc29fa6529e4 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 5 Jan 2013 14:56:32 +0100 Subject: [PATCH 003/266] move to flattr API 0.6 --- ddportfolioservice/templates/base.mako | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ddportfolioservice/templates/base.mako b/ddportfolioservice/templates/base.mako index 648c8f4..3b23a73 100644 --- a/ddportfolioservice/templates/base.mako +++ b/ddportfolioservice/templates/base.mako @@ -33,11 +33,7 @@ License along with this program. If not, see id='debianlogo')}

${_('Debian Member Portfolio Service')}

${h.literal(_('''This service has been inspired by Stefano Zacchiroli's DDPortfolio page in the Debian Wiki. You can create a set of customized links leading to a Debian Member's or package maintainer's information regarding Debian.'''))}

-

-

+

${self.body()} @@ -48,6 +44,10 @@ License along with this program. If not, see

${h.literal(_('''The service is available 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. You can browse the source code or clone it from %(cloneurl)s using git. If you want to translate this service to your language you can contribute at Transifex.''') % dict((('browseurl', 'http://debianstuff.dittberner.info/gitweb.cgi?p=ddportfolioservice.git;a=summary'), ('cloneurl', 'http://debianstuff.dittberner.info/git/ddportfolioservice.git'), ('transifexurl', 'https://www.transifex.com/projects/p/debportfolioservice/'))))}

${_(u'''Copyright © 2009, 2010, 2011, 2012 Jan Dittberner''')}

+ + <%def name="extrahead()"> From e033be09d025ed2d2ad066bed2a63b0fa2790bd7 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 5 Jan 2013 14:58:18 +0100 Subject: [PATCH 004/266] bump version to 0.2.14 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 48fde7b..d168a7f 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ except ImportError: setup( name='ddportfolioservice', - version='0.2.13', + version='0.2.14', description='service to create DDPortfolio URLs', long_description="""This is a service implementation that returns a set of personalized URLs as outlined in From 894d2b21bb9d52fdbcc1e6040a655c01b035cba5 Mon Sep 17 00:00:00 2001 From: Paul Wise Date: Sun, 20 Jan 2013 15:50:29 +0800 Subject: [PATCH 005/266] Fix bugs name search link --- ddportfolioservice/model/ddportfolio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddportfolioservice/model/ddportfolio.ini b/ddportfolioservice/model/ddportfolio.ini index bb07dcf..f941929 100644 --- a/ddportfolioservice/model/ddportfolio.ini +++ b/ddportfolioservice/model/ddportfolio.ini @@ -33,7 +33,7 @@ urls=received,reported,usertags,searchall,wnpp,correspondent,graph received.pattern=http://bugs.debian.org/%(email)s reported.pattern=http://bugs.debian.org/from:%(email)s usertags.pattern=http://bugs.debian.org/cgi-bin/pkgreport.cgi?users=%(email)s -searchall.pattern=http://merkel.debian.org/~don/cgi/search.cgi?phrase=%(name)s;search=search +searchall.pattern=http://bugs-search.debian.org/cgi-bin/search.cgi?phrase=%(name)s;search=search wnpp.pattern=http://qa.debian.org/developer.php?wnpp=%(email)s correspondent.pattern=http://bugs.debian.org/cgi-bin/pkgreport.cgi?correspondent=%(email)s graph.pattern=http://qa.debian.org/data/bts/graphs/by-maint/%(email)s.png From 74c05e4b2cb2a3c37784dcbc311c955899cf96fd Mon Sep 17 00:00:00 2001 From: Paul Wise Date: Sun, 20 Jan 2013 15:58:33 +0800 Subject: [PATCH 006/266] Fix name search link --- ddportfolioservice/model/ddportfolio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddportfolioservice/model/ddportfolio.ini b/ddportfolioservice/model/ddportfolio.ini index f941929..86c85f8 100644 --- a/ddportfolioservice/model/ddportfolio.ini +++ b/ddportfolioservice/model/ddportfolio.ini @@ -88,7 +88,7 @@ urls=debtags,links,website,search,gpgfinger,gpgweb debtags.pattern=http://debtags.debian.net/reports/maint/%(email)s links.pattern=http://www.google.com/search?hl=en&lr=&q=site%%3Adebian.org+%%22%(name)s%%22+-site%%3Anm.debian.org+-site%%3Alintian.debian.org+-site%%3Abugs.debian.org+-site%%3Alists.debian.org+-site%%3Apackages.debian.org+-site%%3Alists.alioth.debian.org+-site%%3Aftp.debian.org++-site%%3Apackages.qa.debian.org++-site%%3Aftp*.*.debian.org+-inurl%%3Adebian.org%%2Fdevel%%2Fpeople.+-inurl%%3Aindices%%2FMaintainers+-inurl%%3Adebian.org%%2Fdebian%%2Fproject++-inurl%%3A%%2Fdists%%2F&btnG=Search website.pattern=http://www.google.com/search?q=site:www.debian.org+%(name)s -search.pattern=http://search.debian.org/?q=%%22%(name)s%%22 +search.pattern=http://search.debian.org/cgi-bin/omega?P=%%22%(name)s%%22 gpgfinger.pattern=finger %(username)s/key@db.debian.org gpgfinger.type=finger gpgfinger.optional=true From c8c1a5570b04be0e3df358a5e4a23f9ed896caaf Mon Sep 17 00:00:00 2001 From: Paul Wise Date: Sun, 20 Jan 2013 16:14:37 +0800 Subject: [PATCH 007/266] Fix the URL for DUCK. --- ddportfolioservice/model/ddportfolio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddportfolioservice/model/ddportfolio.ini b/ddportfolioservice/model/ddportfolio.ini index 86c85f8..7bebdba 100644 --- a/ddportfolioservice/model/ddportfolio.ini +++ b/ddportfolioservice/model/ddportfolio.ini @@ -49,7 +49,7 @@ lintian.pattern=http://lintian.debian.org/maintainer/%(email)s.html lintianfull.pattern=http://lintian.debian.org/full/%(email)s.html piuparts.pattern=http://piuparts.debian.org/sid/maintainer/%(firstchar)s/%(email)s.html patchtracker.pattern=http://patch-tracker.debian.org/email/%(email)s -duck.pattern=http://duck.debian.net/?maintainer=%(email)s +duck.pattern=http://duck.debian.net/?searchstring=%(email)s [lists] urls=dolists,adolists,gmane From f1716a3dbf6c6e0ad37b0e7ba48dfc003cfe18b6 Mon Sep 17 00:00:00 2001 From: Paul Wise Date: Sun, 20 Jan 2013 16:23:00 +0800 Subject: [PATCH 008/266] dns information is public in LDAP, no need for ssh --- ddportfolioservice/model/ddportfolio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ddportfolioservice/model/ddportfolio.ini b/ddportfolioservice/model/ddportfolio.ini index 7bebdba..0c35f10 100644 --- a/ddportfolioservice/model/ddportfolio.ini +++ b/ddportfolioservice/model/ddportfolio.ini @@ -100,8 +100,8 @@ nm.pattern=https://nm.debian.org/public/person/%(username)s # SSH functions urls=owndndoms,miainfo,groupinfo # owned *.debian.net domains -owndndoms.pattern=ssh master.debian.org ldapsearch -u -x -H ldap://db.debian.org -b dc=debian,dc=org uid=%(username)s dnsZoneEntry -owndndoms.type=ssh +owndndoms.pattern=ldapsearch -u -x -H ldap://db.debian.org -b dc=debian,dc=org uid=%(username)s dnsZoneEntry +owndndoms.type=ldapsearch owndndoms.optional=true # MIA information miainfo.pattern=ssh qa.debian.org /srv/qa.debian.org/mia/mia-query %(emailnoq)s From d31e0852e5d8e1400b2b65cd21799fa38473607e Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sun, 20 Jan 2013 10:44:22 +0100 Subject: [PATCH 009/266] bump version number --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index d168a7f..ed08b5e 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # DDPortfolio service setup -# Copyright © 2009, 2010, 2011, 2012 Jan Dittberner +# Copyright © 2009, 2010, 2011, 2012, 2013 Jan Dittberner # # This file is part of DDPortfolio service. # @@ -29,7 +29,7 @@ except ImportError: setup( name='ddportfolioservice', - version='0.2.14', + version='0.2.15', description='service to create DDPortfolio URLs', long_description="""This is a service implementation that returns a set of personalized URLs as outlined in From 8ff89db55729d960da68bdcf2f4a2841cabf5048 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sun, 20 Jan 2013 10:45:26 +0100 Subject: [PATCH 010/266] bump copyright years --- ddportfolioservice/model/ddportfolio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddportfolioservice/model/ddportfolio.ini b/ddportfolioservice/model/ddportfolio.ini index 0c35f10..71b2270 100644 --- a/ddportfolioservice/model/ddportfolio.ini +++ b/ddportfolioservice/model/ddportfolio.ini @@ -1,6 +1,6 @@ # # Configuration for DDPortfolio service -# Copyright © 2009, 2010, 2011, 2012 Jan Dittberner +# Copyright © 2009, 2010, 2011, 2012, 2013 Jan Dittberner # # This file is part of DDPortfolio service. # From 7872900a53573f5a2737c2ad703d358546562285 Mon Sep 17 00:00:00 2001 From: Paul Wise Date: Fri, 15 Feb 2013 09:23:35 +0800 Subject: [PATCH 011/266] Drop unnecessary manual HTML escaping of ampersands. --- ddportfolioservice/model/ddportfolio.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ddportfolioservice/model/ddportfolio.ini b/ddportfolioservice/model/ddportfolio.ini index 71b2270..cadb397 100644 --- a/ddportfolioservice/model/ddportfolio.ini +++ b/ddportfolioservice/model/ddportfolio.ini @@ -53,9 +53,9 @@ duck.pattern=http://duck.debian.net/?searchstring=%(email)s [lists] urls=dolists,adolists,gmane -dolists.pattern=http://lists.debian.org/cgi-bin/search?author=%(name)s&sort=date +dolists.pattern=http://lists.debian.org/cgi-bin/search?author=%(name)s&sort=date adolists.pattern=http://www.google.com/search?q=site%%3Alists.alioth.debian.org+%%22%(name)s%%22 -gmane.pattern=http://search.gmane.org/?email=%(name)s&group=gmane.linux.debian.* +gmane.pattern=http://search.gmane.org/?email=%(name)s&group=gmane.linux.debian.* # debconf list search has a tricky URL format # http://lists.debconf.org/lurker/search \ # /20100510.202949.00000000@au:%(firstname)s,au:%(lastname)s.en.html @@ -75,7 +75,7 @@ nm.pattern=https://nm.debian.org/public/nmstatus/%(username)s dbfinger.pattern=finger %(username)s@db.debian.org dbfinger.type=finger dbfinger.optional=true -db.pattern=http://db.debian.org/search.cgi?uid=%(username)s&dosearch=Search +db.pattern=http://db.debian.org/search.cgi?uid=%(username)s&dosearch=Search db.optional=true alioth.pattern=http://alioth.debian.org/users/%(aliothusername)s/ alioth.optional=true From ee4bcb5a767f5c2b75777ef599fea56af1658e4a Mon Sep 17 00:00:00 2001 From: Paul Wise Date: Fri, 15 Feb 2013 09:23:36 +0800 Subject: [PATCH 012/266] Add new FOAF profiles --- ddportfolioservice/controllers/ddportfolio.py | 1 + ddportfolioservice/model/ddportfolio.ini | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ddportfolioservice/controllers/ddportfolio.py b/ddportfolioservice/controllers/ddportfolio.py index f6fdc45..cef30e8 100644 --- a/ddportfolioservice/controllers/ddportfolio.py +++ b/ddportfolioservice/controllers/ddportfolio.py @@ -90,6 +90,7 @@ developer name on all bug logs)'), 'nm': N_('NM'), 'dbfinger': N_('DB information via finger'), 'db': N_('DB information via HTTP'), + 'webid': N_('FOAF profile'), 'alioth': N_('Alioth'), 'wiki': N_('Wiki'), 'forum': N_('Forum'), diff --git a/ddportfolioservice/model/ddportfolio.ini b/ddportfolioservice/model/ddportfolio.ini index cadb397..2c5cf06 100644 --- a/ddportfolioservice/model/ddportfolio.ini +++ b/ddportfolioservice/model/ddportfolio.ini @@ -70,13 +70,15 @@ alioth.pattern=http://alioth.debian.org/~%(aliothusername)s/ alioth.optional=true [membership] -urls=nm,dbfinger,db,alioth,wiki,forum +urls=nm,dbfinger,db,webid,alioth,wiki,forum nm.pattern=https://nm.debian.org/public/nmstatus/%(username)s dbfinger.pattern=finger %(username)s@db.debian.org dbfinger.type=finger dbfinger.optional=true db.pattern=http://db.debian.org/search.cgi?uid=%(username)s&dosearch=Search db.optional=true +webid.pattern=http://webid.debian.net/maintainers/%(username) +webid.optional=true alioth.pattern=http://alioth.debian.org/users/%(aliothusername)s/ alioth.optional=true wiki.pattern=http://wiki.debian.org/%(wikihomepage)s From b98ff0b48611b01335a891b10aec3241caf6a2f2 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 16 Feb 2013 11:21:23 +0100 Subject: [PATCH 013/266] bump version number --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index ed08b5e..d255fb7 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ except ImportError: setup( name='ddportfolioservice', - version='0.2.15', + version='0.2.16', description='service to create DDPortfolio URLs', long_description="""This is a service implementation that returns a set of personalized URLs as outlined in From d9522187acf1ca2f7d8f799226b236231e13a5d0 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 16 Feb 2013 11:34:04 +0100 Subject: [PATCH 014/266] add missing s to webid.pattern --- ddportfolioservice/model/ddportfolio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddportfolioservice/model/ddportfolio.ini b/ddportfolioservice/model/ddportfolio.ini index 2c5cf06..b5e38db 100644 --- a/ddportfolioservice/model/ddportfolio.ini +++ b/ddportfolioservice/model/ddportfolio.ini @@ -77,7 +77,7 @@ dbfinger.type=finger dbfinger.optional=true db.pattern=http://db.debian.org/search.cgi?uid=%(username)s&dosearch=Search db.optional=true -webid.pattern=http://webid.debian.net/maintainers/%(username) +webid.pattern=http://webid.debian.net/maintainers/%(username)s webid.optional=true alioth.pattern=http://alioth.debian.org/users/%(aliothusername)s/ alioth.optional=true From f11e1d2bc338a99d5eaf909a7151e49af891968c Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 16 Feb 2013 11:34:41 +0100 Subject: [PATCH 015/266] bump version number --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d255fb7..737ca4f 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ except ImportError: setup( name='ddportfolioservice', - version='0.2.16', + version='0.2.16.1', description='service to create DDPortfolio URLs', long_description="""This is a service implementation that returns a set of personalized URLs as outlined in From 5cbc1580156f21fdaf6bf64ee5467d05932db670 Mon Sep 17 00:00:00 2001 From: Paul Wise Date: Fri, 22 Feb 2013 07:55:31 +0800 Subject: [PATCH 016/266] Add a pair of Planet Debian search links --- ddportfolioservice/controllers/ddportfolio.py | 2 ++ ddportfolioservice/model/ddportfolio.ini | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ddportfolioservice/controllers/ddportfolio.py b/ddportfolioservice/controllers/ddportfolio.py index cef30e8..e6bbdb3 100644 --- a/ddportfolioservice/controllers/ddportfolio.py +++ b/ddportfolioservice/controllers/ddportfolio.py @@ -98,6 +98,8 @@ developer name on all bug logs)'), 'miscellaneous': { 'label': N_('Miscellaneous'), 'debtags': N_('debtags'), + 'planetname': N_('Planet Debian (name)'), + 'planetuser': N_('Planet Debian (username)'), 'links': N_('links'), 'website': N_('Debian website'), 'search': N_('Debian search'), diff --git a/ddportfolioservice/model/ddportfolio.ini b/ddportfolioservice/model/ddportfolio.ini index b5e38db..5c49772 100644 --- a/ddportfolioservice/model/ddportfolio.ini +++ b/ddportfolioservice/model/ddportfolio.ini @@ -86,8 +86,11 @@ forum.pattern=http://forums.debian.net/memberlist.php?mode=viewprofile&u=%(forum forum.optional=true [miscellaneous] -urls=debtags,links,website,search,gpgfinger,gpgweb +urls=debtags,links,planetname,planetuser,website,search,gpgfinger,gpgweb debtags.pattern=http://debtags.debian.net/reports/maint/%(email)s +planetname.pattern=http://planet-search.debian.org/cgi-bin/search.cgi?terms=%%22%(name)s%%22 +planetuser.pattern=http://planet-search.debian.org/cgi-bin/search.cgi?terms=%%22%(username)s%%22 +planetuser.optional=true links.pattern=http://www.google.com/search?hl=en&lr=&q=site%%3Adebian.org+%%22%(name)s%%22+-site%%3Anm.debian.org+-site%%3Alintian.debian.org+-site%%3Abugs.debian.org+-site%%3Alists.debian.org+-site%%3Apackages.debian.org+-site%%3Alists.alioth.debian.org+-site%%3Aftp.debian.org++-site%%3Apackages.qa.debian.org++-site%%3Aftp*.*.debian.org+-inurl%%3Adebian.org%%2Fdevel%%2Fpeople.+-inurl%%3Aindices%%2FMaintainers+-inurl%%3Adebian.org%%2Fdebian%%2Fproject++-inurl%%3A%%2Fdists%%2F&btnG=Search website.pattern=http://www.google.com/search?q=site:www.debian.org+%(name)s search.pattern=http://search.debian.org/cgi-bin/omega?P=%%22%(name)s%%22 From 7da151abbed8128582bb931fbdc8698ef659c42b Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sun, 24 Feb 2013 19:38:11 +0100 Subject: [PATCH 017/266] Bump version number --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 737ca4f..723be12 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ except ImportError: setup( name='ddportfolioservice', - version='0.2.16.1', + version='0.2.17', description='service to create DDPortfolio URLs', long_description="""This is a service implementation that returns a set of personalized URLs as outlined in From 9efe6a7b2812bb96cee27fe8ba9932fc152e87d0 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sun, 24 Feb 2013 21:50:56 +0100 Subject: [PATCH 018/266] ignore vim swap files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 77fa001..9da49a7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ data/ +.*.swp *.pyc *.egg-info/ .coverage From 98b7bc26762b99db24d2f7f5013fc3e2626e5faa Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sun, 24 Feb 2013 21:56:02 +0100 Subject: [PATCH 019/266] prepare sphinx documentation building * docs/conf.py: - add sphinx.ext.viewcode to extensions - update copyright years - bump version numbers - explicitly define language * setup.cfg - define output directory and add all_files directive --- docs/conf.py | 10 +++++----- setup.cfg | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index ce686a8..b2c9a85 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,7 +26,7 @@ import sys, os # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc'] +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] # Add any paths that contain templates here, relative to this directory. templates_path = ['.templates'] @@ -42,20 +42,20 @@ master_doc = 'index' # General information about the project. project = u'Debian Developer Portfolio Service' -copyright = u'2009, Jan Dittberner' +copyright = u'2009-2013, Jan Dittberner' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '0.1' +version = '0.2.18' # The full version, including alpha/beta/rc tags. -release = '0.1dev' +release = '0.2.18dev' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +language = 'en' # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: diff --git a/setup.cfg b/setup.cfg index 8b8db3d..3b1d4d5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,6 +7,8 @@ find_links = http://www.pylonshq.com/download/ [build_sphinx] source-dir = docs +build-dir = docs/html +all_files = 1 [publish] doc-dir=docs/html From b000e08b3f3f07a48ee611c3c26a0c3b6228f755 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sun, 24 Feb 2013 21:59:19 +0100 Subject: [PATCH 020/266] add introduction text and credits file --- docs/credits.rst | 22 ++++++++++++++++++++++ docs/index.rst | 20 ++++++++++++++------ 2 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 docs/credits.rst diff --git a/docs/credits.rst b/docs/credits.rst new file mode 100644 index 0000000..74e2dd2 --- /dev/null +++ b/docs/credits.rst @@ -0,0 +1,22 @@ +Credits +======= + +The Debian Member Portfolio Service contains contributions from several people. + +Code +---- + + * Jan Dittberner + * Paul Wise + +Translations +------------ + + * Jan Dittberner + * Daniel Manzano (Brazilian Portuguese) + * Izharul Haq (Indonesian) + * Stéphane Aulery (French) + +If you think your name is missing please tell me (Jan Dittberner) about your +contribution and I'll add you. + diff --git a/docs/index.rst b/docs/index.rst index 39a38d5..28d90aa 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,15 +1,23 @@ -.. Debian Developer Portfolio Service documentation master file, created by sphinx-quickstart on Tue Jan 20 22:27:21 2009. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. +.. Debian Member Portfolio Service documentation master file, created by + sphinx-quickstart on Tue Jan 20 22:27:21 2009. You can adapt this file + completely to your liking, but it should at least contain the root `toctree` + directive. -Welcome to Debian Developer Portfolio Service's documentation! -============================================================== +Debian Member Portfolio Service +=============================== -Contents: +The Debian Member Portfolio Service is a web application that provides links to +information regarding the activities of a person related to the `Debian Project +`_. + +The service was originally implemented and is hosted by Jan Dittberner at +http://portfolio.debian.net/. .. toctree:: :maxdepth: 2 + credits + Indices and tables ================== From 599f10a6bb9fed2de09455556255e79b8de2623f Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sun, 24 Feb 2013 22:01:32 +0100 Subject: [PATCH 021/266] add source reference in docs/sourcecode.rst * ddportfolioservice/controllers/ddportfolio.py - add docstring to DdportfolioController * ddportfolioservice/model/__init__.py - add module docstring * docs/index.rst - add link to sourcecode file * docs/sourcecode.rst - include autogenerated module information --- ddportfolioservice/controllers/ddportfolio.py | 3 + ddportfolioservice/model/__init__.py | 4 + docs/index.rst | 1 + docs/sourcecode.rst | 95 +++++++++++++++++++ 4 files changed, 103 insertions(+) create mode 100644 docs/sourcecode.rst diff --git a/ddportfolioservice/controllers/ddportfolio.py b/ddportfolioservice/controllers/ddportfolio.py index e6bbdb3..4af5597 100644 --- a/ddportfolioservice/controllers/ddportfolio.py +++ b/ddportfolioservice/controllers/ddportfolio.py @@ -37,6 +37,9 @@ log = logging.getLogger(__name__) class DdportfolioController(BaseController): + """ + Main controller for the Debian Member portfolio service. + """ _LABELS = { 'overview': { 'label': N_('Overview'), diff --git a/ddportfolioservice/model/__init__.py b/ddportfolioservice/model/__init__.py index f5029b6..a533c8d 100644 --- a/ddportfolioservice/model/__init__.py +++ b/ddportfolioservice/model/__init__.py @@ -20,3 +20,7 @@ # License along with this program. If not, see # . # +""" +Model classes and model related utilities for the Debian Member Portfolio +service. +""" diff --git a/docs/index.rst b/docs/index.rst index 28d90aa..aadf843 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -16,6 +16,7 @@ http://portfolio.debian.net/. .. toctree:: :maxdepth: 2 + sourcecode credits Indices and tables diff --git a/docs/sourcecode.rst b/docs/sourcecode.rst new file mode 100644 index 0000000..55cce3f --- /dev/null +++ b/docs/sourcecode.rst @@ -0,0 +1,95 @@ +Source documentation +==================== + +The sections below contain mostly autogenerated documentation of the source +code of the Debian Member Portfolio Service. + +Controllers +----------- + +.. automodule:: ddportfolioservice.controllers + :members: + +ddportfolio controller +~~~~~~~~~~~~~~~~~~~~~~ + +.. automodule:: ddportfolioservice.controllers.ddportfolio + :members: + +error controller +~~~~~~~~~~~~~~~~ + +.. automodule:: ddportfolioservice.controllers.error + :members: + +showformscripts controller +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. automodule:: ddportfolioservice.controllers.showformscripts + :members: + +template controller +~~~~~~~~~~~~~~~~~~~ + +.. automodule:: ddportfolioservice.controllers.template + :members: + +Library code +------------ + +.. automodule:: ddportfolioservice.lib + :members: + +app_globals +~~~~~~~~~~~ + +.. automodule:: ddportfolioservice.lib.app_globals + :members: + +base +~~~~ + +.. automodule:: ddportfolioservice.lib.base + :members: + +helpers +~~~~~~~ + +.. automodule:: ddportfolioservice.lib.helpers + :members: + +Model +----- + +.. automodule:: ddportfolioservice.model + :members: + +dddatabuilder +~~~~~~~~~~~~~ + +.. automodule:: ddportfolioservice.model.dddatabuilder + :members: + +form +~~~~ + +.. automodule:: ddportfolioservice.model.form + :members: + +keyfinder +~~~~~~~~~ + +.. automodule:: ddportfolioservice.model.keyfinder + :members: + +keyringanalyzer +~~~~~~~~~~~~~~~ + +.. automodule:: ddportfolioservice.model.keyringanalyzer + :members: + +urlbuilder +~~~~~~~~~~ + +.. automodule:: ddportfolioservice.model.urlbuilder + :members: From 4304c425f76f8b320fdd968d9a9843b4dd1c6ea8 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sun, 24 Feb 2013 22:04:55 +0100 Subject: [PATCH 022/266] add initial development documentation --- docs/.gitignore | 1 + docs/devdocs.rst | 120 +++++++++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 1 + 3 files changed, 122 insertions(+) create mode 100644 docs/.gitignore create mode 100644 docs/devdocs.rst diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..5ccff1a --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +html/ diff --git a/docs/devdocs.rst b/docs/devdocs.rst new file mode 100644 index 0000000..e82c56f --- /dev/null +++ b/docs/devdocs.rst @@ -0,0 +1,120 @@ +Development of Debian Member Portfolio Service +============================================== + +The Debian Member Portfolio Service is implemented in `Python +`_ using the `Pylons +`_ web application +framework. + +The following sections describe how to setup a local development environment +for the Debian Member Portfolio Service. + +All instructions assume that you work on a Debian system. You should use Python +2.7 for development. + +Setup of a local development +---------------------------- + +To start working on the source code you need to have `git`_ installed:: + + sudo aptitude install git + +.. _git: http://www.git-scm.com/ + +The canonical git repository for the Debian Member Portfolio Service is +available at http://debianstuff.dittberner.info/git/ddportfolioservice.git. To +get a clone of the source code you change to a directory of your choice and +invoke git clone:: + + cd ~/src + git clone http://debianstuff.dittberner.info/git/ddportfolioservice.git + +You should use `virtualenv`_ to separate the development environment from your +system wide Python installation. You can install virtualenv using:: + + sudo aptitude install python-virtualenv + +.. _virtualenv: https://pypi.python.org/pypi/virtualenv + +When you have :command:`virtualenv` installed you should create a virtual +environment for Debian Member Portfolio Service development and install the +requirements using `pip `_:: + + mkdir ~/.virtualenvs + virtualenv --distribute ~/.virtualenvs/dmportfolio + . ~/.virtualenvs/dmportfolio/bin/activate + cd ~/src/ddportfolioservice + pip install -r squeezereq.pip + +.. note:: + + The Debian Member Portfolio Service instance at http://portfolio.debian.net/ + is running on a Debian Squeeze server, therefore :file:`squeezereq.pip` + contains dependency versions matching that Debian release. + +The dependency download and installation into the virtual environment takes +some time. + +After you have your virtual environment ready you need to setup the project for +development:: + + python setup.py develop + +Debian Member Portfolio Service needs the JQuery JavaScript library to function +properly. The JQuery library is not included in the git clone and must be +copied into the subdirectory +:file:`ddportfolioservice/public/javascript/jquery`. On Debian systems you can +install the package libjs-jquery and place a symlink to the directory +:file:`/usr/share/javascript` into :file:`ddportfolioservice/public`: :: + + sudo aptitude install libjs-jquery + ln -s /usr/share/javascript ddportfolioservice/public + +Prepare for first startup +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Debian Member Portfolio Service uses data from the Debian keyring to get +information regarding PGP keys and names related to email addresses. Before you +can run the service you need to fetch a copy of the keyring and prepare it for +use by the code. + +.. note:: + + You need rsync and gnupg for these tasks:: + + sudo aptitude install rsync gnupg + +When you have both installed you can run:: + + . ~/.virtualenvs/dmportfolio/bin/activate + ./synckeyrings.sh + python ddportfolioservice/model/keyringanalyzer.py + +The first synchronizes the keyrings in :file:`$HOME/debian/keyring.debian.org` +with files on the `keyring.debian.org `_ host. And +the second generates a key/value database in +:file:`ddportfolioservice/model/keyringcache` that is used by the code. + +Run a development server +~~~~~~~~~~~~~~~~~~~~~~~~ + +Pylons uses PasteScript to run a development server. You can run a development +server using:: + + paster serve --reload development.ini + +The output of this command should look like the following:: + + Starting subprocess with file monitor + Starting server in PID 31377. + serving on http://127.0.0.1:5000 + +You can now access your development server at the URL that is printed by the command. + +If you want to stop the development server press :kbd:`Ctrl + C`. + +Common development tasks +------------------------ + +Add new URL +~~~~~~~~~~~ diff --git a/docs/index.rst b/docs/index.rst index aadf843..192332e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -16,6 +16,7 @@ http://portfolio.debian.net/. .. toctree:: :maxdepth: 2 + devdocs sourcecode credits From f778c21b0e61c0ea810d718c5d475b8953d7ba80 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sun, 24 Feb 2013 22:13:12 +0100 Subject: [PATCH 023/266] move documentation sources to docs/source * docs/source/conf.py - add toplevel directory to Python search path to allow building of documentation using system sphinx installation --- docs/{ => source}/conf.py | 3 ++- docs/{ => source}/credits.rst | 0 docs/{ => source}/devdocs.rst | 0 docs/{ => source}/index.rst | 0 docs/{ => source}/sourcecode.rst | 0 setup.cfg | 2 +- 6 files changed, 3 insertions(+), 2 deletions(-) rename docs/{ => source}/conf.py (98%) rename docs/{ => source}/credits.rst (100%) rename docs/{ => source}/devdocs.rst (100%) rename docs/{ => source}/index.rst (100%) rename docs/{ => source}/sourcecode.rst (100%) diff --git a/docs/conf.py b/docs/source/conf.py similarity index 98% rename from docs/conf.py rename to docs/source/conf.py index b2c9a85..8eb44c9 100644 --- a/docs/conf.py +++ b/docs/source/conf.py @@ -19,7 +19,8 @@ import sys, os # If your extensions are in another directory, add it here. If the directory # is relative to the documentation root, use os.path.abspath to make it # absolute, like shown here. -#sys.path.append(os.path.abspath('.')) +sys.path.append( + os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))) # General configuration # --------------------- diff --git a/docs/credits.rst b/docs/source/credits.rst similarity index 100% rename from docs/credits.rst rename to docs/source/credits.rst diff --git a/docs/devdocs.rst b/docs/source/devdocs.rst similarity index 100% rename from docs/devdocs.rst rename to docs/source/devdocs.rst diff --git a/docs/index.rst b/docs/source/index.rst similarity index 100% rename from docs/index.rst rename to docs/source/index.rst diff --git a/docs/sourcecode.rst b/docs/source/sourcecode.rst similarity index 100% rename from docs/sourcecode.rst rename to docs/source/sourcecode.rst diff --git a/setup.cfg b/setup.cfg index 3b1d4d5..e1069a2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -6,7 +6,7 @@ tag_svn_revision = true find_links = http://www.pylonshq.com/download/ [build_sphinx] -source-dir = docs +source-dir = docs/source build-dir = docs/html all_files = 1 From 1fc616adf73950139c6ad0e88f275a936fdc88ff Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sun, 24 Feb 2013 22:25:23 +0100 Subject: [PATCH 024/266] use docs/build instead of docs/html --- docs/.gitignore | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/.gitignore b/docs/.gitignore index 5ccff1a..567609b 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1 +1 @@ -html/ +build/ diff --git a/setup.cfg b/setup.cfg index e1069a2..6af5237 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,7 +7,7 @@ find_links = http://www.pylonshq.com/download/ [build_sphinx] source-dir = docs/source -build-dir = docs/html +build-dir = docs/build all_files = 1 [publish] From 9706f2777c7f3cf2135febe98cb40ad1bca64d08 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sun, 24 Feb 2013 22:52:36 +0100 Subject: [PATCH 025/266] add documentation on how to add a new URL --- docs/source/devdocs.rst | 48 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/docs/source/devdocs.rst b/docs/source/devdocs.rst index e82c56f..a07365c 100644 --- a/docs/source/devdocs.rst +++ b/docs/source/devdocs.rst @@ -118,3 +118,51 @@ Common development tasks Add new URL ~~~~~~~~~~~ + +Debian Member Portfolio Service uses a ini style configuration file +:file:`ddportfolioservice/model/ddportfolio.ini` to configure the generated URL +patterns. The actual URL generation is done in +:py:class:`~ddportfolioservice.controllers.ddportfolio.DdportfolioController` +in the +:py:meth:`~ddportfolioservice.controllers.ddportfolio.DdportfolioController.urllist` +method. + +If you want to add a new URL type you have to add a line in +:file:`ddportfolio.ini` and an entry in +:py:class:`~ddportfolioservice.controllers.ddportfolio.DdportfolioController`'s +:py:attr:`~ddportfolioservice.controllers.ddportfolio.DdportfolioController._LABELS` +dictionary. The top level dictionary keys correspond to sections in the ini +file. The dictionary values are dictionaries themselves that contain a special +key ``label`` that defines the label of the section in the output and keys for +each entry to be rendered in that section. The values in these sub-dictionaries +are strings marked for translation using the :py:func:`~pylons.i18n._` function from +:py:mod:`pylons.i18n`. + +The patterns in :file:`ddportfolio.ini` can contain the following placeholders +that are filled at runtime: + +================== ======================================== +Placeholder Replacement +================== ======================================== +%(aliothusername)s user name on `alioth.debian.org`_ +%(email)s email address (URL encoded) +%(emailnoq)s email address +%(firstchar)s first character of the email address +%(forumsid)d forum user id +%(gpgfp)s GNUPG/PGP key fingerprint +%(name)s full name (i.e. John Smith) +%(username)s Debian user name +%(wikihomepage)s full name in camel case (i.e. JohnSmith) +================== ======================================== + +.. _alioth.debian.org: http://alioth.debian.org/ + +The replacement of placeholders is performed in the +:py:meth:`~ddportfolioservice.controllers.ddportfolio.DdportfolioController.urllist` +method. And uses data from the Debian keyring. Access to the pre-parsed keyring +data is performed using the +:py:func:`~ddportfolioservice.model.dddatabuilder.build_data` function of the +module :py:mod:`ddportfolioservice.model.dddatabuilder`, which uses several +helper functions from :py:mod:`ddportfolioservice.model.keyfinder` to access +the key information. + From 8ac405446336d8cd8f9bdc1e08c3644a7edc6b8e Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sun, 24 Feb 2013 22:54:39 +0100 Subject: [PATCH 026/266] bump version number --- docs/source/conf.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 8eb44c9..4919270 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -52,7 +52,7 @@ copyright = u'2009-2013, Jan Dittberner' # The short X.Y version. version = '0.2.18' # The full version, including alpha/beta/rc tags. -release = '0.2.18dev' +release = '0.2.18' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index 723be12..4504706 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ except ImportError: setup( name='ddportfolioservice', - version='0.2.17', + version='0.2.18', description='service to create DDPortfolio URLs', long_description="""This is a service implementation that returns a set of personalized URLs as outlined in From e82e241158925d81517d98b0ff2b6ff0e22192b3 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sun, 24 Feb 2013 22:56:09 +0100 Subject: [PATCH 027/266] update changelog --- ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ChangeLog b/ChangeLog index 4504ca7..75384e8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2013-02-24 Jan Dittberner + * add sphinx documentation + * applied multiple patches by Paul Wise + 2012-12-08 Jan Dittberner * include patch for Debian URL checker by Paul Wise From 57bc445b5a55738d0cfeaa16d02041c01cef71d2 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Fri, 9 Aug 2013 20:54:02 +0200 Subject: [PATCH 028/266] fix typo in German translation thanks to Simon Kainz --- .../i18n/de/LC_MESSAGES/ddportfolioservice.mo | Bin 7356 -> 7354 bytes .../i18n/de/LC_MESSAGES/ddportfolioservice.po | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ddportfolioservice/i18n/de/LC_MESSAGES/ddportfolioservice.mo b/ddportfolioservice/i18n/de/LC_MESSAGES/ddportfolioservice.mo index a38e3206bc5f77df5b4cc9d235a689409906102a..97dba73746daf434f8f9002251289ba41cba11d0 100644 GIT binary patch delta 593 zcmXZZJ4nM|5Ww-Xwf3Rawzie{fMP90v=UN;rh?EeqKhavIVn1}li+3s!NJu*1@Qrj z;8X|*ilD2D;HD1lii2Qr(ZT;=Amn%7m)zZ#%Z+_)H%9$VuZUbGLqiG`d9y zWf6z5jvcs%Tyn-OiC5T#4;aN)?8Fbu;|~sCmY0KA!2nJt#gP=jEE{oLMQyl_Iow7q z&_F%F6Sks{q%sCk*HzTUQ>cv>FpMimiqz4Eo2d1-Q1kXv&i_dc+0aRxdfuWIdcg?3 zAs-=4)Cq*rBK?@cXDVBmZsD0B;%7fgu{O-3=8vH^v{4T*iG4Vy^PeZE;R)WMPGXs- znz)8N=%9{n7iaJYb%gJppPt_sWB(W1G0G`*5(erdvfjFc6RdMp0{u4|s0|M=gy*P< m4V0awc*d;-E+VmF!7LR_J7byU@#2VSx%t?!&%IB4h5rB&l|3f_ delta 593 zcmXZZJ1j$C6u|ML540YA=p$T`M%*+FP3|p29}Ce169$t(B21!_#B>=X2Ac_qv}n>c|+j|ibG zVg@VNiHFEXPWg)AHHPp3yYLme@dMNNg9B*t=Qf-~KhDI&kvPFDi3qNu4%|c&_fQ+u zQ7`a}KJ-yk!~p8Kj5>GRwFL{$@t(ZZrw@?R`P%ki!2F^PKa|G*H!#mVXEc2@t zZeS9(QCD|>(^x}Y;k)an>oSo5C;!?~=T%Ub!AJzBK#!\n" "Language-Team: de \n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" @@ -316,7 +316,7 @@ msgstr "Eingabe der persönlichen Informationen" #: ddportfolioservice/templates/showform.mako:30 #: ddportfolioservice/templates/showurls.mako:28 msgid "Debian Member Portfolio" -msgstr "Debian-Mitgliedererportfolio" +msgstr "Debian-Mitgliederportfolio" #: ddportfolioservice/templates/showform.mako:36 msgid "Email address:" From 2301d3420225651b981c15d1017098fd718f3fd9 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Fri, 9 Aug 2013 21:03:34 +0200 Subject: [PATCH 029/266] bump version number --- docs/source/conf.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 4919270..54103d2 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -50,7 +50,7 @@ copyright = u'2009-2013, Jan Dittberner' # built documents. # # The short X.Y version. -version = '0.2.18' +version = '0.2.18.1' # The full version, including alpha/beta/rc tags. release = '0.2.18' diff --git a/setup.py b/setup.py index 4504706..2640725 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ except ImportError: setup( name='ddportfolioservice', - version='0.2.18', + version='0.2.18.1', description='service to create DDPortfolio URLs', long_description="""This is a service implementation that returns a set of personalized URLs as outlined in From 875eb57d3528e9029ecc1ea85dd9bbcd8dac5022 Mon Sep 17 00:00:00 2001 From: Olivier Berger Date: Fri, 15 Nov 2013 14:28:47 +0100 Subject: [PATCH 030/266] Change for more useful documentation --- README.txt | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/README.txt b/README.txt index 2861c89..32c73e0 100644 --- a/README.txt +++ b/README.txt @@ -1,20 +1,11 @@ -This file is for you to describe the ddportfolioservice -application. Typically you would include information such as the -information below: -Installation and Setup -====================== +This is the source code for the Debian Member Portfolio Service +application [0]. -Install ``ddportfolioservice`` using easy_install:: +Cf. https://debian-member-portfolio-service.readthedocs.org/ for more +documentation (or its source in docs/source/devdocs.rst), including +how to configure a development environment. - easy_install ddportfolioservice -Make a config file as follows:: +[0] http://wiki.debian.org/DDPortfolio - paster make-config ddportfolioservice config.ini - -Tweak the config file as appropriate and then setup the application:: - - paster setup-app config.ini - -Then you are ready to go. From 2752c2e98d6d0ab7c6420ddd7a0275f0dabad342 Mon Sep 17 00:00:00 2001 From: Olivier Berger Date: Fri, 15 Nov 2013 14:31:46 +0100 Subject: [PATCH 031/266] Adopt the way which is described in /usr/share/doc/gnupg/DETAILS.gz which expands first line, and use email.utils.parseaddr() --- ddportfolioservice/model/keyringanalyzer.py | 27 ++++++--------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/ddportfolioservice/model/keyringanalyzer.py b/ddportfolioservice/model/keyringanalyzer.py index cc501c6..b3304a7 100644 --- a/ddportfolioservice/model/keyringanalyzer.py +++ b/ddportfolioservice/model/keyringanalyzer.py @@ -35,6 +35,7 @@ import os.path import logging import subprocess import sys +import email.utils def _get_keyrings(): @@ -58,22 +59,8 @@ def _parse_uid(uid): Parse a uid of the form 'Real Name ' into email and realname parts. """ - uid = uid.strip() - # First, strip comment - s = uid.find('(') - e = uid.find(')') - if s >= 0 and e >= 0: - uid = uid[:s] + uid[e + 1:] - s = uid.find('<') - e = uid.find('>') - email = None - if s >= 0 and e >= 0: - email = uid[s + 1:e] - uid = uid[:s] + uid[e + 1:] - uid = uid.strip() - if not email and uid.find('@') >= 0: - email, uid = uid, email - return (uid, email) + (uid, mail) = email.utils.parseaddr(uid) + return (uid, mail) resultdict = {} @@ -85,6 +72,7 @@ def _get_canonical(key): def _add_to_result(key, newvalue): + logging.debug("adding %s: %s", key, newvalue) thekey = _get_canonical(key) if newvalue not in resultdict[thekey]: resultdict[thekey].append(newvalue) @@ -95,10 +83,10 @@ def process_keyrings(): file.""" for keyring in _get_keyrings(): logging.debug("get data from %s", keyring) - proc = subprocess.Popen(["gpg", "--no-default-keyring", + proc = subprocess.Popen(["gpg", "--no-options", "--no-default-keyring", "--no-expensive-trust-checks", "--keyring", keyring, "--list-keys", - "--with-colons", "--fingerprint"], + "--with-colons", "--fixed-list-mode", "--with-fingerprint", "--with-fingerprint"], stdout=subprocess.PIPE) fpr = None entry = None @@ -108,11 +96,10 @@ def process_keyrings(): uid = None if items[0] == 'pub': fpr = entry = None - lastpub = items[9].strip() + lastpub = items[4].strip() continue elif items[0] == 'fpr': fpr = items[9].strip() - uid = lastpub elif items[0] == 'uid': uid = items[9].strip() else: From 8ebe8bfede929882cc0ab3fc3b5de7f1e9f68605 Mon Sep 17 00:00:00 2001 From: Olivier Berger Date: Fri, 15 Nov 2013 14:32:24 +0100 Subject: [PATCH 032/266] Exclude revoked ids : can't trust them, IMHO --- ddportfolioservice/model/keyringanalyzer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ddportfolioservice/model/keyringanalyzer.py b/ddportfolioservice/model/keyringanalyzer.py index b3304a7..9f3aa69 100644 --- a/ddportfolioservice/model/keyringanalyzer.py +++ b/ddportfolioservice/model/keyringanalyzer.py @@ -101,6 +101,8 @@ def process_keyrings(): elif items[0] == 'fpr': fpr = items[9].strip() elif items[0] == 'uid': + if items[1] == 'r': + continue uid = items[9].strip() else: continue From d12111b4009801e6a401c98304791fa66662fcce Mon Sep 17 00:00:00 2001 From: Olivier Berger Date: Fri, 15 Nov 2013 14:34:23 +0100 Subject: [PATCH 033/266] Add some test code to dump contents of the cache --- ddportfolioservice/model/keyfinder.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/ddportfolioservice/model/keyfinder.py b/ddportfolioservice/model/keyfinder.py index d857f4d..71f584a 100644 --- a/ddportfolioservice/model/keyfinder.py +++ b/ddportfolioservice/model/keyfinder.py @@ -26,6 +26,7 @@ given keyring. """ import logging import time +import sys db = None cachetimestamp = 0 @@ -84,3 +85,25 @@ def getLoginByFingerprint(fpr): Gets the login associated with the given fingerprint if available. """ return _get_cached('login:fpr:%s' % fpr) + +def _dump_cache(): + cache = _get_keyring_cache() + fprs = [] + for key in cache.keys(): + if key.startswith('email:fpr:'): + fpr = key.replace('email:fpr:', '') + if not fpr in fprs: + fprs.append(fpr) + + for fpr in fprs: + login = getLoginByFingerprint(fpr) + email = _get_cached('email:fpr:%s' % fpr) + name = _get_cached('name:fpr:%s' % fpr) + + print fpr, login, ':' + print ' ', name, email + + +if __name__ == '__main__': + logging.basicConfig(stream=sys.stderr, level=logging.WARNING) + _dump_cache() From a9bde6350aedec2b3a7492aa80bdc91629602e7d Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Fri, 15 Nov 2013 21:41:22 +0100 Subject: [PATCH 034/266] give credits to Olivier Berger --- docs/source/credits.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/credits.rst b/docs/source/credits.rst index 74e2dd2..2744e27 100644 --- a/docs/source/credits.rst +++ b/docs/source/credits.rst @@ -8,6 +8,7 @@ Code * Jan Dittberner * Paul Wise + * Olivier Berger Translations ------------ From ecb9689ca5b597e7d3b9966eef13b261651f4f2c Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Fri, 15 Nov 2013 21:44:20 +0100 Subject: [PATCH 035/266] bump version to 0.2.19 --- docs/source/conf.py | 4 ++-- setup.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 54103d2..f00d642 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -50,9 +50,9 @@ copyright = u'2009-2013, Jan Dittberner' # built documents. # # The short X.Y version. -version = '0.2.18.1' +version = '0.2.19' # The full version, including alpha/beta/rc tags. -release = '0.2.18' +release = '0.2.19' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index 2640725..1396e1e 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ except ImportError: setup( name='ddportfolioservice', - version='0.2.18.1', + version='0.2.19', description='service to create DDPortfolio URLs', long_description="""This is a service implementation that returns a set of personalized URLs as outlined in From de3dda922b39f5706ab11d6c58c5ad301d6559dd Mon Sep 17 00:00:00 2001 From: Paul Wise Date: Sun, 17 Nov 2013 14:43:38 +0800 Subject: [PATCH 036/266] Add contributor information links --- ddportfolioservice/controllers/ddportfolio.py | 1 + ddportfolioservice/model/ddportfolio.ini | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ddportfolioservice/controllers/ddportfolio.py b/ddportfolioservice/controllers/ddportfolio.py index 4af5597..14196e9 100644 --- a/ddportfolioservice/controllers/ddportfolio.py +++ b/ddportfolioservice/controllers/ddportfolio.py @@ -109,6 +109,7 @@ developer name on all bug logs)'), 'gpgfinger': N_('GPG public key via finger'), 'gpgweb': N_('GPG public key via HTTP'), 'nm': N_('NM, AM participation'), + 'contrib': N_('Contribution information'). }, 'ssh': { 'label': N_('Information reachable via ssh (for Debian Members)'), diff --git a/ddportfolioservice/model/ddportfolio.ini b/ddportfolioservice/model/ddportfolio.ini index 5c49772..7dd4073 100644 --- a/ddportfolioservice/model/ddportfolio.ini +++ b/ddportfolioservice/model/ddportfolio.ini @@ -86,7 +86,7 @@ forum.pattern=http://forums.debian.net/memberlist.php?mode=viewprofile&u=%(forum forum.optional=true [miscellaneous] -urls=debtags,links,planetname,planetuser,website,search,gpgfinger,gpgweb +urls=debtags,links,planetname,planetuser,website,search,gpgfinger,gpgweb,contrib debtags.pattern=http://debtags.debian.net/reports/maint/%(email)s planetname.pattern=http://planet-search.debian.org/cgi-bin/search.cgi?terms=%%22%(name)s%%22 planetuser.pattern=http://planet-search.debian.org/cgi-bin/search.cgi?terms=%%22%(username)s%%22 @@ -100,6 +100,8 @@ gpgfinger.optional=true gpgweb.pattern=http://db.debian.org/fetchkey.cgi?fingerprint=%(gpgfp)s gpgweb.optional=true nm.pattern=https://nm.debian.org/public/person/%(username)s +contrib.pattern=https://contributors.debian.org/contributors/contributor/%(aliothusername)s +contrib.optional=true [ssh] # SSH functions From 755a2dc5ea3779f1d937a73ad031f293a20713c9 Mon Sep 17 00:00:00 2001 From: Olivier Berger Date: Mon, 18 Nov 2013 13:59:49 +0100 Subject: [PATCH 037/266] Revert back some name/mail processing for cases where the uid is not strictly an email --- ddportfolioservice/model/keyringanalyzer.py | 54 +++++++++++++++------ 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/ddportfolioservice/model/keyringanalyzer.py b/ddportfolioservice/model/keyringanalyzer.py index 9f3aa69..c82772e 100644 --- a/ddportfolioservice/model/keyringanalyzer.py +++ b/ddportfolioservice/model/keyringanalyzer.py @@ -53,14 +53,39 @@ def _get_keyrings(): keyrings.sort() return keyrings - def _parse_uid(uid): """ Parse a uid of the form 'Real Name ' into email and realname parts. """ - (uid, mail) = email.utils.parseaddr(uid) - return (uid, mail) + + # First try with the Python library, but it doesn't always catch everything + (name, mail) = email.utils.parseaddr(uid) + if (not name) and (not mail): + logging.warning("malformed uid %s", uid) + if (not name) or (not mail): + logging.debug("strange uid %s: '%s' - <%s>", uid, name, mail) + # Try and do better than the python library + if not '@' in mail: + uid = uid.strip() + # First, strip comment + s = uid.find('(') + e = uid.find(')') + if s >= 0 and e >= 0: + uid = uid[:s] + uid[e + 1:] + s = uid.find('<') + e = uid.find('>') + mail = None + if s >= 0 and e >= 0: + mail = uid[s + 1:e] + uid = uid[:s] + uid[e + 1:] + uid = uid.strip() + if not mail and uid.find('@') >= 0: + mail, uid = uid, mail + + name = uid + logging.debug("corrected: '%s' - <%s>", name, mail) + return (name, mail) resultdict = {} @@ -107,19 +132,20 @@ def process_keyrings(): else: continue # Do stuff with 'uid' - uid, email = _parse_uid(uid) - if email: - if email.endswith('@debian.org'): - login = email[0:-len('@debian.org')] - _add_to_result('login:email:%s' % email, login) - _add_to_result('login:fpr:%s' % fpr, login) - _add_to_result('fpr:login:%s' % login, fpr) - _add_to_result('fpr:email:%s' % email, fpr) - _add_to_result('email:fpr:%s' % fpr, email) + if uid: + (uid, mail) = _parse_uid(uid) + if mail: + if mail.endswith('@debian.org'): + login = mail[0:-len('@debian.org')] + _add_to_result('login:email:%s' % mail, login) + _add_to_result('login:fpr:%s' % fpr, login) + _add_to_result('fpr:login:%s' % login, fpr) + _add_to_result('fpr:email:%s' % mail, fpr) + _add_to_result('email:fpr:%s' % fpr, mail) if uid: _add_to_result('name:fpr:%s' % fpr, uid) - if email: - _add_to_result('name:email:%s' % email, uid) + if mail: + _add_to_result('name:email:%s' % mail, uid) retcode = proc.wait() if retcode != 0: logging.error("subprocess ended with return code %d", retcode) From a8213b789bedac518dc56ddd293c280e6aefceee Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Wed, 20 Nov 2013 17:42:46 +0100 Subject: [PATCH 038/266] fix syntax error --- ddportfolioservice/controllers/ddportfolio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddportfolioservice/controllers/ddportfolio.py b/ddportfolioservice/controllers/ddportfolio.py index 14196e9..81fcd55 100644 --- a/ddportfolioservice/controllers/ddportfolio.py +++ b/ddportfolioservice/controllers/ddportfolio.py @@ -109,7 +109,7 @@ developer name on all bug logs)'), 'gpgfinger': N_('GPG public key via finger'), 'gpgweb': N_('GPG public key via HTTP'), 'nm': N_('NM, AM participation'), - 'contrib': N_('Contribution information'). + 'contrib': N_('Contribution information'), }, 'ssh': { 'label': N_('Information reachable via ssh (for Debian Members)'), From 98399ec1bd54d111d426e34e9a0cc02a4c94c915 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Wed, 20 Nov 2013 17:44:12 +0100 Subject: [PATCH 039/266] bump version --- docs/source/conf.py | 4 ++-- setup.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index f00d642..d0d6179 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -50,9 +50,9 @@ copyright = u'2009-2013, Jan Dittberner' # built documents. # # The short X.Y version. -version = '0.2.19' +version = '0.2.20' # The full version, including alpha/beta/rc tags. -release = '0.2.19' +release = '0.2.20' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index 1396e1e..5811d7d 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ except ImportError: setup( name='ddportfolioservice', - version='0.2.19', + version='0.2.20', description='service to create DDPortfolio URLs', long_description="""This is a service implementation that returns a set of personalized URLs as outlined in From cac34c879f139eb8d29a47c3de13af369e4cdb6c Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Fri, 10 Jan 2014 23:07:41 +0000 Subject: [PATCH 040/266] add requirements file with Debian Wheezy version --- wheezyreq.pip | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 wheezyreq.pip diff --git a/wheezyreq.pip b/wheezyreq.pip new file mode 100644 index 0000000..f177096 --- /dev/null +++ b/wheezyreq.pip @@ -0,0 +1,20 @@ +Babel==0.9.6 +Beaker==1.6.3 +FormEncode==1.2.4 +Mako==0.7.0 +MarkupSafe==0.15 +Paste==1.7.5.1 +PasteDeploy==1.5.0 +PasteScript==1.7.5 +Pygments==1.5 +Pylons==1.0 +Routes==1.13 +Tempita==0.5.1 +WebError==0.10.3 +WebHelpers==1.3 +WebOb==1.1.1 +WebTest==1.3.4 +argparse==1.2.1 +nose==1.1.2 +simplejson==2.5.2 +wsgiref==0.1.2 From 2bcb98fcf26c332b3aa9b50e5272813319ba3697 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Fri, 10 Jan 2014 23:10:29 +0000 Subject: [PATCH 041/266] refer to wheezyreq.pip and remove squeezereq.pip --- docs/source/devdocs.rst | 4 ++-- squeezereq.pip | 20 -------------------- 2 files changed, 2 insertions(+), 22 deletions(-) delete mode 100644 squeezereq.pip diff --git a/docs/source/devdocs.rst b/docs/source/devdocs.rst index a07365c..d0360bd 100644 --- a/docs/source/devdocs.rst +++ b/docs/source/devdocs.rst @@ -44,12 +44,12 @@ requirements using `pip `_:: virtualenv --distribute ~/.virtualenvs/dmportfolio . ~/.virtualenvs/dmportfolio/bin/activate cd ~/src/ddportfolioservice - pip install -r squeezereq.pip + pip install -r wheezyreq.pip .. note:: The Debian Member Portfolio Service instance at http://portfolio.debian.net/ - is running on a Debian Squeeze server, therefore :file:`squeezereq.pip` + is running on a Debian Wheezy server, therefore :file:`wheezyreq.pip` contains dependency versions matching that Debian release. The dependency download and installation into the virtual environment takes diff --git a/squeezereq.pip b/squeezereq.pip deleted file mode 100644 index 165e508..0000000 --- a/squeezereq.pip +++ /dev/null @@ -1,20 +0,0 @@ -Babel==0.9.4 -Beaker==1.5.4 -FormEncode==1.2.2 -Mako==0.3.4 -MarkupSafe==0.9.2 -Paste==1.7.5.1 -PasteDeploy==1.3.3 -PasteScript==1.7.3 -Pygments==1.3.1 -Pylons==0.10 -Routes==1.12.3 -Tempita==0.4 -WebError==0.10.2 -WebHelpers==1.1 -WebOb==0.9.8 -WebTest==1.2.1 -argparse==1.1 -nose==0.11.1 -simplejson==2.1.1 -wsgiref==0.1.2 From a74c778258a872a39f09568597cb4b9564c8fb8b Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 11 Jan 2014 00:02:56 +0000 Subject: [PATCH 042/266] ignore .ropeproject --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 9da49a7..08da140 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ data/ *.pyc *.egg-info/ .coverage +.ropeproject/ From 275885cb4187d7df5b72182f9fba091cdd21e3b5 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 11 Jan 2014 00:03:09 +0000 Subject: [PATCH 043/266] improve keyring analyzer - define separate gnupg homedir as gnupghome - update file comments in ddportfolioservice/model/ddportfolio.ini and ddportfolioservice/model/keyringanalyzer.py to reflect current copyright years and project name - keyringanalyzer.py: - refactor to reduce function complexity - fix PEP8 violations - use gnupghome setting - switch to SafeConfigParser --- ddportfolioservice/model/ddportfolio.ini | 23 ++-- ddportfolioservice/model/keyringanalyzer.py | 117 ++++++++++++-------- 2 files changed, 81 insertions(+), 59 deletions(-) diff --git a/ddportfolioservice/model/ddportfolio.ini b/ddportfolioservice/model/ddportfolio.ini index 7dd4073..3545b44 100644 --- a/ddportfolioservice/model/ddportfolio.ini +++ b/ddportfolioservice/model/ddportfolio.ini @@ -1,24 +1,25 @@ # -# Configuration for DDPortfolio service -# Copyright © 2009, 2010, 2011, 2012, 2013 Jan Dittberner +# Configuration for Debian Member Portfolio service # -# This file is part of DDPortfolio service. +# Copyright © 2009-2014 Jan Dittberner # -# DDPortfolio service is free software: you can redistribute it and/or -# modify 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 file is part of the Debian Member Portfolio service. # -# DDPortfolio service 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. +# Debian Member Portfolio service is free software: you can redistribute it +# and/or modify 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. +# +# Debian Member Portfolio service 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 # . # [DEFAULT] +gnupghome=~/debian/gnupghome keyring.dir=~/debian/keyring.debian.org/keyrings urlbuilder.sections=overview,bugs,build,qa,lists,files,membership, miscellaneous,ssh,ubuntu diff --git a/ddportfolioservice/model/keyringanalyzer.py b/ddportfolioservice/model/keyringanalyzer.py index c82772e..4f134a4 100644 --- a/ddportfolioservice/model/keyringanalyzer.py +++ b/ddportfolioservice/model/keyringanalyzer.py @@ -1,20 +1,21 @@ # -*- python -*- # -*- coding: utf-8 -*- # -# DDPortfolio service application key ring analyzer tool -# Copyright © 2009, 2010, 2011, 2012 Jan Dittberner +# Debian Member Portfolio service application key ring analyzer tool # -# This file is part of DDPortfolio service. +# Copyright © 2009-2014 Jan Dittberner # -# DDPortfolio service is free software: you can redistribute it and/or -# modify it under the terms of the GNU Affero General Public License -# as published by the Free Software Foundation, either version 3 of +# This file is part of the Debian Member Portfolio service. +# +# Debian Member Portfolio service is free software: you can redistribute it +# and/or modify 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. # -# DDPortfolio service 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. +# Debian Member Portfolio service 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 @@ -38,27 +39,28 @@ import sys import email.utils +CONFIG = ConfigParser.SafeConfigParser() + + def _get_keyrings(): """ Gets the available keyring files from the keyring directory configured in ddportfolio.ini. """ - my_config = ConfigParser.ConfigParser() - my_config.readfp(pkg_resources.resource_stream( - __name__, 'ddportfolio.ini')) - keyringdir = os.path.expanduser(my_config.get('DEFAULT', 'keyring.dir')) + keyringdir = os.path.expanduser(CONFIG.get('DEFAULT', 'keyring.dir')) logging.debug("keyring dir is %s", keyringdir) keyrings = glob.glob(os.path.join(keyringdir, '*.gpg')) keyrings.extend(glob.glob(os.path.join(keyringdir, '*.pgp'))) keyrings.sort() return keyrings + def _parse_uid(uid): """ Parse a uid of the form 'Real Name ' into email and realname parts. """ - + # First try with the Python library, but it doesn't always catch everything (name, mail) = email.utils.parseaddr(uid) if (not name) and (not mail): @@ -103,49 +105,63 @@ def _add_to_result(key, newvalue): resultdict[thekey].append(newvalue) +def _handle_mail(mail, fpr): + if mail.endswith('@debian.org'): + login = mail[0:-len('@debian.org')] + _add_to_result('login:email:%s' % mail, login) + _add_to_result('login:fpr:%s' % fpr, login) + _add_to_result('fpr:login:%s' % login, fpr) + _add_to_result('fpr:email:%s' % mail, fpr) + _add_to_result('email:fpr:%s' % fpr, mail) + + +def _handle_uid(uid, fpr): + # Do stuff with 'uid' + if uid: + (uid, mail) = _parse_uid(uid) + if mail: + _handle_mail(mail, fpr) + if uid: + _add_to_result('name:fpr:%s' % fpr, uid) + if mail: + _add_to_result('name:email:%s' % mail, uid) + return fpr + + +def process_gpg_list_keys_line(line, fpr): + """ + Process a line of gpg --list-keys --with-colon output. + """ + items = line.split(':') + if items[0] == 'pub': + return None + if items[0] == 'fpr': + return items[9].strip() + if items[0] == 'uid': + if items[1] == 'r': + return fpr + return _handle_uid(items[9].strip(), fpr) + else: + return fpr + + def process_keyrings(): """Process the keyrings and store the extracted data in an anydbm file.""" for keyring in _get_keyrings(): logging.debug("get data from %s", keyring) - proc = subprocess.Popen(["gpg", "--no-options", "--no-default-keyring", + proc = subprocess.Popen([ + "gpg", "--no-options", "--no-default-keyring", + "--homedir", os.path.expanduser( + CONFIG.get('DEFAULT', 'gnupghome')), "--no-expensive-trust-checks", "--keyring", keyring, "--list-keys", - "--with-colons", "--fixed-list-mode", "--with-fingerprint", "--with-fingerprint"], + "--with-colons", "--fixed-list-mode", "--with-fingerprint", + "--with-fingerprint"], stdout=subprocess.PIPE) fpr = None - entry = None - lastpub = None for line in proc.stdout.readlines(): - items = line.split(':') - uid = None - if items[0] == 'pub': - fpr = entry = None - lastpub = items[4].strip() - continue - elif items[0] == 'fpr': - fpr = items[9].strip() - elif items[0] == 'uid': - if items[1] == 'r': - continue - uid = items[9].strip() - else: - continue - # Do stuff with 'uid' - if uid: - (uid, mail) = _parse_uid(uid) - if mail: - if mail.endswith('@debian.org'): - login = mail[0:-len('@debian.org')] - _add_to_result('login:email:%s' % mail, login) - _add_to_result('login:fpr:%s' % fpr, login) - _add_to_result('fpr:login:%s' % login, fpr) - _add_to_result('fpr:email:%s' % mail, fpr) - _add_to_result('email:fpr:%s' % fpr, mail) - if uid: - _add_to_result('name:fpr:%s' % fpr, uid) - if mail: - _add_to_result('name:email:%s' % mail, uid) + fpr = process_gpg_list_keys_line(line, fpr) retcode = proc.wait() if retcode != 0: logging.error("subprocess ended with return code %d", retcode) @@ -158,4 +174,9 @@ def process_keyrings(): if __name__ == '__main__': logging.basicConfig(stream=sys.stderr, level=logging.WARNING) + CONFIG.readfp(pkg_resources.resource_stream( + __name__, 'ddportfolio.ini')) + gpghome = os.path.expanduser(CONFIG.get('DEFAULT', 'gnupghome')) + if not os.path.isdir(gpghome): + os.makedirs(gpghome, 0700) process_keyrings() From 4e18b2bd53a98faec91ae2b6cdaebece384f0e33 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 11 Jan 2014 01:33:45 +0100 Subject: [PATCH 044/266] update templates - bump copyright years and update program name - fix escape call to work with webhelpers 1.3 --- ddportfolioservice/templates/base.mako | 29 +++++++++++----------- ddportfolioservice/templates/showform.mako | 28 ++++++++++----------- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/ddportfolioservice/templates/base.mako b/ddportfolioservice/templates/base.mako index 3b23a73..1e2dd8b 100644 --- a/ddportfolioservice/templates/base.mako +++ b/ddportfolioservice/templates/base.mako @@ -3,23 +3,22 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <%doc> Base template for XHTML templates. -Copyright © 2009, 2010 Jan Dittberner +Copyright © 2009-2014 Jan Dittberner -This file is part of DDPortfolio service. +This file is part of the Debian Member Portfolio service. -DDPortfolio service is free software: you can redistribute it and/or -modify 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. +Debian Member Portfolio service is free software: you can redistribute it +and/or modify 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. -DDPortfolio service 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. +Debian Member Portfolio service 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 -. +You should have received a copy of the GNU Affero General Public License along +with this program. If not, see . @@ -42,10 +41,10 @@ License along with this program. If not, see ${h.image(h.url('/images/agplv3-88x31.png'), _('AGPL - Free Software'), 88, 31, id='agpllogo')}

${h.literal(_('''The service is available 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. You can browse the source code or clone it from %(cloneurl)s using git. If you want to translate this service to your language you can contribute at Transifex.''') % dict((('browseurl', 'http://debianstuff.dittberner.info/gitweb.cgi?p=ddportfolioservice.git;a=summary'), ('cloneurl', 'http://debianstuff.dittberner.info/git/ddportfolioservice.git'), ('transifexurl', 'https://www.transifex.com/projects/p/debportfolioservice/'))))}

-

${_(u'''Copyright © 2009, 2010, 2011, 2012 Jan Dittberner''')}

+

${_(u'''Copyright © 2009-2014 Jan Dittberner''')}

diff --git a/ddportfolioservice/templates/showform.mako b/ddportfolioservice/templates/showform.mako index 6ee353a..6485e49 100644 --- a/ddportfolioservice/templates/showform.mako +++ b/ddportfolioservice/templates/showform.mako @@ -2,23 +2,23 @@ <%inherit file="base.mako" /> <%doc> Template for the data input form. -Copyright © 2009, 2010 Jan Dittberner -This file is part of DDPortfolio service. +Copyright © 2009-2014 Jan Dittberner -DDPortfolio service is free software: you can redistribute it and/or -modify 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 file is part of the Debian Member Portfolio service. -DDPortfolio service 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. +Debian Member Portfolio service is free software: you can redistribute it +and/or modify 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. -You should have received a copy of the GNU Affero General Public -License along with this program. If not, see -. +Debian Member Portfolio service 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 . <%def name="titleaddon()"> - ${_('Enter your personal information')} @@ -40,7 +40,7 @@ ${h.form(h.url(action='urllist', controller='ddportfolio'), method='get')} % endif
${h.text('email', - h.escape(request.params.get('email', None), True), id='email')}
+ h.escape(request.params.get('email', None)), id='email')}
+ +
+
+ {{ form.name }} +
+
+
+ {{ form.gpgfp }} +
+
+
+ {{ form.username }} +
+
+
+ {{ form.nonddemail }} +
+
+
+ {{ form.aliothusername }} +
+
+
+ {{ form.wikihomepage }} +
+
+
+ {{ form.forumsid }} +
+
+
+ {% for subfield in form.mode %} + {{ subfield.label }} {{ subfield }} + {% endfor %}
+ +
{% endblock %} diff --git a/debianmemberportfolio/templates/showform.mako b/debianmemberportfolio/templates/showform.mako deleted file mode 100644 index 32a8233..0000000 --- a/debianmemberportfolio/templates/showform.mako +++ /dev/null @@ -1,164 +0,0 @@ -## -- coding: utf-8 -- \ -<%inherit file="base.mako" /> -<%doc> -Template for the data input form. - -Copyright © 2009-2014 Jan Dittberner - -This file is part of the Debian Member Portfolio service. - -Debian Member Portfolio service is free software: you can redistribute it -and/or modify 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. - -Debian Member Portfolio service 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 . - -<%def name="titleaddon()"> - - ${_('Enter your personal information')} - -<%def name="extrahead()">${h.javascript_link('/javascript/jquery/jquery.js', -h.url(controller='showformscripts', action='index'))} -${h.form(h.url(action='urllist', controller='portfolio'), method='get')} -
- ${_('Debian Member Portfolio')} -
-
- ${h.text('email', - h.escape(request.params.get('email', None)), id='email')}
-
- -
-
- ${h.text('name', - h.escape(request.params.get('name', None)), id='name')}
-
-
-
- ${h.text('gpgfp', - h.escape(request.params.get('gpgfp', None)), - id='gpgfp')}
-
-
-
- ${h.text('username', - h.escape(request.params.get('username', None)), - id='username')}
-
-
-
- ${h.text('nonddemail', - h.escape(request.params.get('nonddemail', None)), - id='nonddemail')}
-
-
-
- ${h.text('aliothusername', - h.escape(request.params.get('username', None)), - id='aliothusername')}
-
-
-
- ${h.text('wikihomepage', - h.escape(request.params.get('wikihomepage', None)), - id='wikihomepage')}
-
-
-
- ${h.text('forumsid', - h.escape(request.params.get('forumsid', None)), - id='forumsid')}
-
-
-
- ${_('HTML')} ${h.radio('mode', 'html', - checked=(request.params.get('mode', - 'html') == 'html'))} ${_('JSON')} ${h.radio('mode', - 'json', checked=(request.params.get('mode', 'html') == 'json'))}
- ${h.submit('submit', value=_('Build Debian Member Portfolio URLs'))} -
-
-${h.end_form()} From b7fe1328bb98f78fa4da061df63de06fb6ebd9b2 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Thu, 12 Nov 2015 21:11:48 +0100 Subject: [PATCH 090/266] Add result view implementation This commit implements the result view and template. - fix Python3 configparser interpolation error in portfolio.ini - debianmemberportfolio.model.urlbuilder ported to Python3 - add showurls.html as a direct Jinja port of showurls.mako - implement functionality in debianmemberportfolio.views.result --- debianmemberportfolio/model/portfolio.ini | 2 +- debianmemberportfolio/model/urlbuilder.py | 22 ++- debianmemberportfolio/templates/showurls.html | 61 +++++++ debianmemberportfolio/views.py | 166 +++++++++++++++++- 4 files changed, 238 insertions(+), 13 deletions(-) create mode 100644 debianmemberportfolio/templates/showurls.html diff --git a/debianmemberportfolio/model/portfolio.ini b/debianmemberportfolio/model/portfolio.ini index c2bcb7a..097042f 100644 --- a/debianmemberportfolio/model/portfolio.ini +++ b/debianmemberportfolio/model/portfolio.ini @@ -83,7 +83,7 @@ webid.optional=true alioth.pattern=https://alioth.debian.org/users/%(aliothusername)s/ alioth.optional=true wiki.pattern=https://wiki.debian.org/%(wikihomepage)s -forum.pattern=http://forums.debian.net/memberlist.php?mode=viewprofile&u=%(forumsid)d +forum.pattern=http://forums.debian.net/memberlist.php?mode=viewprofile&u=%(forumsid)s forum.optional=true [miscellaneous] diff --git a/debianmemberportfolio/model/urlbuilder.py b/debianmemberportfolio/model/urlbuilder.py index 33178a5..26e786d 100644 --- a/debianmemberportfolio/model/urlbuilder.py +++ b/debianmemberportfolio/model/urlbuilder.py @@ -3,7 +3,7 @@ # # Debian Member Portfolio Service url builder # -# Copyright © 2009-2014 Jan Dittberner +# Copyright © 2009-2015 Jan Dittberner # # This file is part of the Debian Member Portfolio Service. # @@ -26,15 +26,18 @@ URLs using the given information and the URL patterns defined in portfolio.ini. """ -from ConfigParser import ConfigParser, InterpolationMissingOptionError +from configparser import ConfigParser, InterpolationMissingOptionError +from encodings.utf_8 import StreamReader as UTF8StreamReader + import pkg_resources from debianmemberportfolio.model import keyfinder -from urllib import quote_plus -from pylons.i18n.translation import _, N_ +from urllib.parse import quote_plus +from flask.ext.babel import gettext as _, lazy_gettext as N_ my_config = ConfigParser() -my_config.readfp(pkg_resources.resource_stream(__name__, 'portfolio.ini')) +my_config.read_file(UTF8StreamReader( + pkg_resources.resource_stream(__name__, 'portfolio.ini'))) _FIELDNAMES_MAP = { 'email': N_('Email address'), @@ -62,14 +65,15 @@ def _build_quoted_fields(fields): Take a dictionary of raw field values and quote the values if required. """ qfields = {} - for key, value in fields.iteritems(): + for key, value in fields.items(): if value is not None: - if isinstance(value, unicode): + if isinstance(value, str): qfields[key] = quote_plus(value.encode('utf8')) elif isinstance(value, str): qfields[key] = quote_plus(value) else: qfields[key] = value + qfields[key] = qfields[key].replace('%', '%%') if 'gpgfp' not in qfields: fpr = keyfinder.getFingerprintByEmail(fields['email'].encode('utf8')) @@ -97,8 +101,8 @@ def build_urls(fields): data.append( ['url', section, entry, my_config.get(section, entry.name + '.pattern', - False, qfields)]) - except InterpolationMissingOptionError, e: + raw=False, vars=qfields)]) + except InterpolationMissingOptionError as e: if not entry.optional: if e.reference in _FIELDNAMES_MAP: data.append(['error', section, entry, diff --git a/debianmemberportfolio/templates/showurls.html b/debianmemberportfolio/templates/showurls.html new file mode 100644 index 0000000..4b5165b --- /dev/null +++ b/debianmemberportfolio/templates/showurls.html @@ -0,0 +1,61 @@ +{% extends "base.html" %} +{# +Template for the url output page. +Copyright © 2009-2015 Jan Dittberner + +This file is part of Debian Member Portfolio Service. + +Debian Member Portfolio Service is free software: you can redistribute it +and/or modify 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. + +Debian Member Portfolio Service 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 . +#} +{% block title %}{{ super() }} - {{ _('Your personal links') }}{% endblock %} +{% block body %}{{ super() }} +{% if urldata %} +
+ {{ _('Debian Member Porfolio') }} + + + + + + {% for row in urldata %} + {% if row[0] == 'section' %} + + {% set urlclass = 'odd' %} + {% elif row[0] == 'error' %} + + + + + {% else %} + + + + + {% if urlclass == "odd" %}{% set urlclass = "even" %}{% else %}{% set urlclass = "odd" %}{% endif %} + {% endif %} + {% endfor %} + +
{{ _('Usage') }}{{ _('URL') }}
{{ row[4] }}{{ _('Error during URL creation:') }} + {{ row[3]|replace("\n", "
") }}
{{ row[4]|safe }} + {% if row[2].type == 'url' %} + {{ row[3]|truncate(120) }} + {% else %} + {{ row[3] }} + {% endif %} +
+
+{% endif %} +

{{ _('Restart') }}

+{% endblock body %} + diff --git a/debianmemberportfolio/views.py b/debianmemberportfolio/views.py index a8fa654..70455db 100644 --- a/debianmemberportfolio/views.py +++ b/debianmemberportfolio/views.py @@ -1,14 +1,144 @@ +# -*- python -*- +# -*- coding: utf-8 -*- +# +# Debian Member Portfolio Service views +# +# Copyright © 2015 Jan Dittberner +# +# This file is part of the Debian Member Portfolio Service. +# +# Debian Member Portfolio Service is free software: you can redistribute it +# and/or modify 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. +# +# Debian Member Portfolio Service 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 . +# import json import logging from debianmemberportfolio import app, babel from flask import g, make_response, request, render_template, abort +from flask.ext.babel import gettext as _, lazy_gettext as N_ from config import LANGUAGES from .forms import DeveloperData, DeveloperDataRequest from .model import dddatabuilder +from .model.urlbuilder import build_urls log = logging.getLogger(__name__) +#: This dictionary defines groups of labeled portfolio items. +_LABELS = { + 'overview': { + 'label': N_('Overview'), + 'ddpo': N_("Debian Member's Package Overview"), + 'alladdresses': N_("""Debian Member's Package Overview +... showing all email addresses"""), + }, + 'bugs': { + 'label': N_('Bugs'), + 'received': N_('''bugs received +(note: co-maintainers not listed, see \ +#430986)'''), + 'reported': N_('bugs reported'), + 'usertags': N_('user tags'), + 'searchall': N_('all messages (i.e., full text search for \ +developer name on all bug logs)'), + 'wnpp': N_('WNPP'), + 'correspondent': N_('correspondent for bugs'), + 'graph': N_('one year open bug history graph'), + }, + 'build': { + 'label': N_('Build'), + 'buildd': N_('buildd.d.o'), + 'igloo': N_('igloo'), + }, + 'qa': { + 'label': N_('Quality Assurance'), + 'dmd': N_('maintainer dashboard'), + 'lintian': N_('lintian reports'), + 'lintianfull': N_('full lintian reports (i.e. including \ +"info"-level messages)'), + 'piuparts': N_('piuparts'), + 'patchtracker': N_('Debian patch tracking system'), + 'duck': N_('Debian Url ChecKer'), + }, + 'lists': { + 'label': N_('Mailing Lists'), + 'dolists': N_('lists.d.o'), + 'adolists': N_('lists.a.d.o'), + 'gmane': N_('gmane'), + }, + 'files': { + 'label': N_('Files'), + 'people': N_('people.d.o'), + 'oldpeople': N_('oldpeople'), + 'alioth': N_('Alioth'), + }, + 'membership': { + 'label': N_('Membership'), + 'nm': N_('NM'), + 'dbfinger': N_('DB information via finger'), + 'db': N_('DB information via HTTP'), + 'webid': N_('FOAF profile'), + 'alioth': N_('Alioth'), + 'wiki': N_('Wiki'), + 'forum': N_('Forum'), + }, + 'miscellaneous': { + 'label': N_('Miscellaneous'), + 'debtags': N_('debtags'), + 'planetname': N_('Planet Debian (name)'), + 'planetuser': N_('Planet Debian (username)'), + 'links': N_('links'), + 'website': N_('Debian website'), + 'search': N_('Debian search'), + 'gpgfinger': N_('GPG public key via finger'), + 'gpgweb': N_('GPG public key via HTTP'), + 'nm': N_('NM, AM participation'), + 'contrib': N_('Contribution information'), + }, + 'ssh': { + 'label': N_('Information reachable via ssh (for Debian Members)'), + 'owndndoms': N_('owned debian.net domains'), + 'miainfo': N_('MIA database information'), + 'groupinfo': N_('Group membership information'), + }, + 'ubuntu': { + 'label': N_('Ubuntu'), + 'ubuntudiff': N_('Available patches from Ubuntu'), + }, +} + +#: list of field name tuples for Debian Maintainers +DM_TUPLES = (('name', 'name'), + ('gpgfp', 'gpgfp'), + ('nonddemail', 'email')) + +#: list of field name tuples for Debian Developers +DD_TUPLES = (('username', 'username'), + ('aliothusername', 'username')) + + +def _get_label(section, url=None): + if section in _LABELS: + if url: + if url in _LABELS[section]: + return _LABELS[section][url] + elif 'label' in _LABELS[section]: + return _LABELS[section]['label'] + if url: + return "%s.%s" % (section, url) + return section + @babel.localeselector def get_locale(): @@ -23,8 +153,6 @@ def before_request(): @app.route('/') def index(): form = DeveloperData() - # TODO: replicate behavior of - # debianmemberportfolio.controllers.portfolio.PortfolioController.index return render_template('showform.html', form=form) @@ -32,7 +160,39 @@ def index(): def urllist(): form = DeveloperData(request.values) if form.validate(): - return render_template('showurls.html') + fields = dddatabuilder.build_data(form.data['email']) + rp = request.values + + if fields['type'] in (dddatabuilder.TYPE_DD, dddatabuilder.TYPE_DM): + for dmtuple in DM_TUPLES: + if not dmtuple[0] in rp or not rp[dmtuple[0]]: + rp[dmtuple[0]] = fields[dmtuple[1]] + if fields['type'] == dddatabuilder.TYPE_DD: + for ddtuple in DD_TUPLES: + if not ddtuple[0] in rp or not rp[ddtuple[0]]: + rp[ddtuple[0]] = fields[ddtuple[1]] + if form.data['wikihomepage'] is None: + log.debug('generate wikihomepage from name') + form.data['wikihomepage'] = "".join([ + part.capitalize() for part in form.data['name'].split() + ]) + + data = build_urls(form.data) + + if form.data['mode'] == 'json': + response = make_response(json.dumps(dict( + [("{}.{}".format(entry[1], entry[2].name), entry[3]) + for entry in data if entry[0] == 'url']))) + response.headers['Content-Type'] = 'application/json' + return response + + for entry in data: + if entry[0] in ('url', 'error'): + entry.append(_get_label(entry[1], entry[2].name)) + elif entry[0] == 'section': + entry.append(_get_label(entry[1])) + + return render_template('showurls.html', urldata=data) return render_template('showform.html', form=form) From c9ae85c2c1840f9bd8ad5ebacadcbc926024ac8c Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Thu, 12 Nov 2015 22:18:23 +0100 Subject: [PATCH 091/266] Remove Pylons remains --- attic/config/__init__.py | 22 -- attic/config/deployment.ini_tmpl | 60 ----- attic/config/environment.py | 75 ------- attic/config/middleware.py | 95 -------- attic/config/routing.py | 58 ----- debianmemberportfolio/controllers/__init__.py | 22 -- debianmemberportfolio/controllers/error.py | 70 ------ .../controllers/portfolio.py | 212 ------------------ .../controllers/showformscripts.py | 75 ------- debianmemberportfolio/controllers/template.py | 55 ----- debianmemberportfolio/lib/__init__.py | 22 -- debianmemberportfolio/lib/app_globals.py | 43 ---- debianmemberportfolio/lib/base.py | 55 ----- debianmemberportfolio/lib/helpers.py | 35 --- debianmemberportfolio/model/form.py | 51 ----- debianmemberportfolio/templates/base.mako | 52 ----- .../templates/showformscript.mako | 122 ---------- debianmemberportfolio/templates/showurls.mako | 67 ------ debianmemberportfolio/tests/__init__.py | 59 ----- .../tests/functional/__init__.py | 22 -- .../tests/functional/test_portfolio.py | 43 ---- .../tests/functional/test_showformscripts.py | 44 ---- debianmemberportfolio/tests/test_models.py | 22 -- development.ini | 73 ------ jessiereq.pip | 29 --- test.ini | 21 -- 26 files changed, 1504 deletions(-) delete mode 100644 attic/config/__init__.py delete mode 100644 attic/config/deployment.ini_tmpl delete mode 100644 attic/config/environment.py delete mode 100644 attic/config/middleware.py delete mode 100644 attic/config/routing.py delete mode 100644 debianmemberportfolio/controllers/__init__.py delete mode 100644 debianmemberportfolio/controllers/error.py delete mode 100644 debianmemberportfolio/controllers/portfolio.py delete mode 100644 debianmemberportfolio/controllers/showformscripts.py delete mode 100644 debianmemberportfolio/controllers/template.py delete mode 100644 debianmemberportfolio/lib/__init__.py delete mode 100644 debianmemberportfolio/lib/app_globals.py delete mode 100644 debianmemberportfolio/lib/base.py delete mode 100644 debianmemberportfolio/lib/helpers.py delete mode 100644 debianmemberportfolio/model/form.py delete mode 100644 debianmemberportfolio/templates/base.mako delete mode 100644 debianmemberportfolio/templates/showformscript.mako delete mode 100644 debianmemberportfolio/templates/showurls.mako delete mode 100644 debianmemberportfolio/tests/__init__.py delete mode 100644 debianmemberportfolio/tests/functional/__init__.py delete mode 100644 debianmemberportfolio/tests/functional/test_portfolio.py delete mode 100644 debianmemberportfolio/tests/functional/test_showformscripts.py delete mode 100644 debianmemberportfolio/tests/test_models.py delete mode 100644 development.ini delete mode 100644 jessiereq.pip delete mode 100644 test.ini diff --git a/attic/config/__init__.py b/attic/config/__init__.py deleted file mode 100644 index 7900219..0000000 --- a/attic/config/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- python -*- -# -*- coding: utf-8 -*- -# -# Debian Member Portfolio Service config package -# -# Copyright © 2009-2014 Jan Dittberner -# -# This file is part of the Debian Member Portfolio Service. -# -# Debian Member Portfolio Service is free software: you can redistribute it -# and/or modify 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. -# -# Debian Member Portfolio Service 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 . -# diff --git a/attic/config/deployment.ini_tmpl b/attic/config/deployment.ini_tmpl deleted file mode 100644 index 116ca29..0000000 --- a/attic/config/deployment.ini_tmpl +++ /dev/null @@ -1,60 +0,0 @@ -# -# Debian Member Portfolio Service - Pylons configuration -# -# The %(here)s variable will be replaced with the parent directory of this file -# -[DEFAULT] -debug = true -email_to = you@yourdomain.com -smtp_server = localhost -error_email_from = paste@localhost - -[server:main] -use = egg:Paste#http -host = 0.0.0.0 -port = 5000 - -[app:main] -use = egg:debianmemberportfolio -full_stack = true -static_files = true - -cache_dir = %(here)s/data -beaker.session.key = debianmemberportfolio -beaker.session.secret = ${app_instance_secret} -app_instance_uuid = ${app_instance_uuid} - -# If you'd like to fine-tune the individual locations of the cache data dirs -# for the Cache data, or the Session saves, un-comment the desired settings -# here: -#beaker.cache.data_dir = %(here)s/data/cache -#beaker.session.data_dir = %(here)s/data/sessions - -# WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* -# Debug mode will enable the interactive debugging tool, allowing ANYONE to -# execute malicious code after an exception is raised. -set debug = false - - -# Logging configuration -[loggers] -keys = root - -[handlers] -keys = console - -[formatters] -keys = generic - -[logger_root] -level = INFO -handlers = console - -[handler_console] -class = StreamHandler -args = (sys.stderr,) -level = NOTSET -formatter = generic - -[formatter_generic] -format = %(asctime)s %(levelname)-5.5s [%(name)s] [%(threadName)s] %(message)s diff --git a/attic/config/environment.py b/attic/config/environment.py deleted file mode 100644 index feabd91..0000000 --- a/attic/config/environment.py +++ /dev/null @@ -1,75 +0,0 @@ -# -*- python -*- -# -*- coding: utf-8 -*- -# -# Debian Member Portfolio Service environment configuration -# -# Copyright © 2009-2014 Jan Dittberner -# -# This file is part of the Debian Member Portfolio Service. -# -# Debian Member Portfolio Service is free software: you can redistribute it -# and/or modify 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. -# -# Debian Member Portfolio Service 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 . -# -""" -Pylons environment configuration - -""" - -import os - -from mako.lookup import TemplateLookup -from pylons.configuration import PylonsConfig -from pylons.error import handle_mako_error - -import debianmemberportfolio.lib.app_globals as app_globals -import debianmemberportfolio.lib.helpers -from debianmemberportfolio.config.routing import make_map - - -def load_environment(global_conf, app_conf): - """ - Configures the Pylons environment via the ``pylons.config`` object. - """ - config = PylonsConfig() - - # Pylons paths - root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - paths = dict(root=root, - controllers=os.path.join(root, 'controllers'), - static_files=os.path.join(root, 'public'), - templates=[os.path.join(root, 'templates')]) - - # Initialize config with the basic options - config.init_app( - global_conf, app_conf, package='debianmemberportfolio', paths=paths) - - config['routes.map'] = make_map(config) - config['pylons.app_globals'] = app_globals.Globals(config) - config['pylons.h'] = debianmemberportfolio.lib.helpers - - # Setup cache object as early as possible - import pylons - pylons.cache._push_object(config['pylons.app_globals'].cache) - - # Create the Mako TemplateLookup, with the default auto-escaping - config['pylons.app_globals'].mako_lookup = TemplateLookup( - directories=paths['templates'], - error_handler=handle_mako_error, - module_directory=os.path.join(app_conf['cache_dir'], 'templates'), - input_encoding='utf-8', default_filters=['escape'], - imports=['from webhelpers.html import escape']) - - # CONFIGURATION OPTIONS HERE (note: all config options will override - # any Pylons config options) - - return config diff --git a/attic/config/middleware.py b/attic/config/middleware.py deleted file mode 100644 index 9dd80ae..0000000 --- a/attic/config/middleware.py +++ /dev/null @@ -1,95 +0,0 @@ -# -*- python -*- -# -*- coding: utf-8 -*- -# -# Debian Member Portfolio Service middleware configuration -# -# Copyright © 2009-2014 Jan Dittberner -# -# This file is part of the Debian Member Portfolio Service. -# -# Debian Member Portfolio Service is free software: you can redistribute it -# and/or modify 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. -# -# Debian Member Portfolio Service 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 . -# -""" -Pylons middleware initialization - -""" - -from beaker.middleware import SessionMiddleware -from paste.cascade import Cascade -from paste.registry import RegistryManager -from paste.urlparser import StaticURLParser -from paste.deploy.converters import asbool -from pylons.middleware import ErrorHandler, StatusCodeRedirect -from pylons.wsgiapp import PylonsApp -from routes.middleware import RoutesMiddleware - -from debianmemberportfolio.config.environment import load_environment - - -def make_app(global_conf, full_stack=True, static_files=True, **app_conf): - """ - Create a Pylons WSGI application and return it - - ``global_conf`` - The inherited configuration for this application. Normally from - the [DEFAULT] section of the Paste ini file. - - ``full_stack`` - Whether this application provides a full WSGI stack (by default, - meaning it handles its own exceptions and errors). Disable - full_stack when this application is "managed" by another WSGI - middleware. - - ``static_files`` - Whether this application serves its own static files; disable - when another web server is responsible for serving them. - - ``app_conf`` - The application's local configuration. Normally specified in - the [app:] section of the Paste ini file (where - defaults to main). - - """ - # Configure the Pylons environment - config = load_environment(global_conf, app_conf) - - # The Pylons WSGI app - app = PylonsApp(config=config) - - # Routing/Session/Cache Middleware - app = RoutesMiddleware(app, config['routes.map']) - app = SessionMiddleware(app, config) - - # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares) - - if asbool(full_stack): - # Handle Python exceptions - app = ErrorHandler(app, global_conf, **config['pylons.errorware']) - - # Display error documents for 401, 403, 404 status codes (and - # 500 when debug is disabled) - if asbool(config['debug']): - app = StatusCodeRedirect(app) - else: - app = StatusCodeRedirect(app, [400, 401, 403, 404, 500]) - - # Establish the Registry for this application - app = RegistryManager(app) - - if asbool(static_files): - # Serve static files - static_app = StaticURLParser(config['pylons.paths']['static_files']) - app = Cascade([static_app, app]) - app.config = config - return app diff --git a/attic/config/routing.py b/attic/config/routing.py deleted file mode 100644 index 39a9d38..0000000 --- a/attic/config/routing.py +++ /dev/null @@ -1,58 +0,0 @@ -# -*- python -*- -# -*- coding: utf-8 -*- -# -# Debian Member Portfolio Service routing configuration -# -# Copyright © 2009-2014 Jan Dittberner -# -# This file is part of the Debian Member Portfolio Service. -# -# Debian Member Portfolio Service is free software: you can redistribute it -# and/or modify 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. -# -# Debian Member Portfolio Service 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 . -# -""" -Routes configuration - -The more specific and detailed routes should be defined first so they -may take precedent over the more generic routes. For more information -refer to the routes manual at https://routes.readthedocs.org/ - -""" - -from routes import Mapper - - -def make_map(config): - """ - Create, configure and return the routes Mapper - - """ - map = Mapper(directory=config['pylons.paths']['controllers'], - always_scan=config['debug'], explicit=True) - map.minimization = False - - # The ErrorController route (handles 404/500 error pages); it should - # likely stay at the top, ensuring it can always be resolved - map.connect('/error/{action}', controller='error') - map.connect('/error/{action}/{id}', controller='error') - - # CUSTOM ROUTES HERE - map.connect('/', controller='portfolio', action='index') - map.connect('/result', controller='portfolio', action='urllist') - map.connect('/htmlformhelper.js', controller='showformscripts', - action='index') - - map.connect('/{controller}/{action}') - map.connect('/{controller}/{action}/{id}') - - return map diff --git a/debianmemberportfolio/controllers/__init__.py b/debianmemberportfolio/controllers/__init__.py deleted file mode 100644 index eda4d33..0000000 --- a/debianmemberportfolio/controllers/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- python -*- -# -*- coding: utf-8 -*- -# -# Debian Member Portfolio Service controllers package -# -# Copyright © 2009-2014 Jan Dittberner -# -# This file is part of the Debian Member Portfolio Service. -# -# Debian Member Portfolio Service is free software: you can redistribute it -# and/or modify 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. -# -# Debian Member Portfolio Service 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 . -# diff --git a/debianmemberportfolio/controllers/error.py b/debianmemberportfolio/controllers/error.py deleted file mode 100644 index 4047bb5..0000000 --- a/debianmemberportfolio/controllers/error.py +++ /dev/null @@ -1,70 +0,0 @@ -# -*- python -*- -# -*- coding: utf-8 -*- -# -# Debian Member Portfolio Service ErrorController -# -# Copyright © 2009-2014 Jan Dittberner -# -# This file is part of the Debian Member Portfolio Service. -# -# Debian Member Portfolio Service is free software: you can redistribute it -# and/or modify 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. -# -# Debian Member Portfolio Service 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 . -# -import cgi - -from paste.urlparser import PkgResourcesParser -from pylons import request -from pylons.controllers.util import forward -from pylons.middleware import error_document_template -from webhelpers.html.builder import literal - -from debianmemberportfolio.lib.base import BaseController - - -class ErrorController(BaseController): - """Generates error documents as and when they are required. - - The ErrorDocuments middleware forwards to ErrorController when error - related status codes are returned from the application. - - This behaviour can be altered by changing the parameters to the - ErrorDocuments middleware in your config/middleware.py file. - """ - - def document(self): - """Render the error document""" - resp = request.environ.get('pylons.original_response') - content = literal(resp.body) or cgi.escape( - request.GET.get('message', '')) - page = error_document_template % \ - dict(prefix=request.environ.get('SCRIPT_NAME', ''), - code=cgi.escape( - request.GET.get('code', str(resp.status_int))), - message=content) - return page - - def img(self, id): - """Serve Pylons' stock images""" - return self._serve_file('/'.join(['media/img', id])) - - def style(self, id): - """Serve Pylons' stock stylesheets""" - return self._serve_file('/'.join(['media/style', id])) - - def _serve_file(self, path): - """ - Call Paste's FileApp (a WSGI application) to serve the file at - the specified path - """ - request.environ['PATH_INFO'] = '/%s' % path - return forward(PkgResourcesParser('pylons', 'pylons')) diff --git a/debianmemberportfolio/controllers/portfolio.py b/debianmemberportfolio/controllers/portfolio.py deleted file mode 100644 index 5539edc..0000000 --- a/debianmemberportfolio/controllers/portfolio.py +++ /dev/null @@ -1,212 +0,0 @@ -# -*- python -*- -# -*- coding: utf-8 -*- -# -# Debian Member Portfolio Service PortfolioController -# -# Copyright © 2009-2014 Jan Dittberner -# -# This file is part of the Debian Member Portfolio Service. -# -# Debian Member Portfolio Service is free software: you can redistribute it -# and/or modify 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. -# -# Debian Member Portfolio Service 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 . -# -""" -This module defines the PortfolioController class used to render the portfolio -of a person. -""" - -import logging -import simplejson - -from pylons import request, response, tmpl_context as c -from pylons.i18n import N_, _ -import formencode.api -import formencode.validators - -from debianmemberportfolio.lib.base import BaseController, render -from debianmemberportfolio.model.form import DDDataRequest, DeveloperData -from debianmemberportfolio.model.urlbuilder import build_urls -from debianmemberportfolio.model import dddatabuilder - -log = logging.getLogger(__name__) - - -class PortfolioController(BaseController): - """ - Main controller for the Debian Member Portfolio Service. - """ - #: This dictionary defines groups of labeled portfolio items. - _LABELS = { - 'overview': { - 'label': N_('Overview'), - 'ddpo': N_("Debian Member's Package Overview"), - 'alladdresses': N_("""Debian Member's Package Overview -... showing all email addresses"""), - }, - 'bugs': { - 'label': N_('Bugs'), - 'received': N_('''bugs received -(note: co-maintainers not listed, see \ -#430986)'''), - 'reported': N_('bugs reported'), - 'usertags': N_('user tags'), - 'searchall': N_('all messages (i.e., full text search for \ -developer name on all bug logs)'), - 'wnpp': N_('WNPP'), - 'correspondent': N_('correspondent for bugs'), - 'graph': N_('one year open bug history graph'), - }, - 'build': { - 'label': N_('Build'), - 'buildd': N_('buildd.d.o'), - 'igloo': N_('igloo'), - }, - 'qa': { - 'label': N_('Quality Assurance'), - 'dmd': N_('maintainer dashboard'), - 'lintian': N_('lintian reports'), - 'lintianfull': N_('full lintian reports (i.e. including \ -"info"-level messages)'), - 'piuparts': N_('piuparts'), - 'patchtracker': N_('Debian patch tracking system'), - 'duck': N_('Debian Url ChecKer'), - }, - 'lists': { - 'label': N_('Mailing Lists'), - 'dolists': N_('lists.d.o'), - 'adolists': N_('lists.a.d.o'), - 'gmane': N_('gmane'), - }, - 'files': { - 'label': N_('Files'), - 'people': N_('people.d.o'), - 'oldpeople': N_('oldpeople'), - 'alioth': N_('Alioth'), - }, - 'membership': { - 'label': N_('Membership'), - 'nm': N_('NM'), - 'dbfinger': N_('DB information via finger'), - 'db': N_('DB information via HTTP'), - 'webid': N_('FOAF profile'), - 'alioth': N_('Alioth'), - 'wiki': N_('Wiki'), - 'forum': N_('Forum'), - }, - 'miscellaneous': { - 'label': N_('Miscellaneous'), - 'debtags': N_('debtags'), - 'planetname': N_('Planet Debian (name)'), - 'planetuser': N_('Planet Debian (username)'), - 'links': N_('links'), - 'website': N_('Debian website'), - 'search': N_('Debian search'), - 'gpgfinger': N_('GPG public key via finger'), - 'gpgweb': N_('GPG public key via HTTP'), - 'nm': N_('NM, AM participation'), - 'contrib': N_('Contribution information'), - }, - 'ssh': { - 'label': N_('Information reachable via ssh (for Debian Members)'), - 'owndndoms': N_('owned debian.net domains'), - 'miainfo': N_('MIA database information'), - 'groupinfo': N_('Group membership information'), - }, - 'ubuntu': { - 'label': N_('Ubuntu'), - 'ubuntudiff': N_('Available patches from Ubuntu'), - }, - } - - #: list of field name tuples for Debian Maintainers - DM_TUPLES = (('name', 'name'), - ('gpgfp', 'gpgfp'), - ('nonddemail', 'email')) - - #: list of field name tuples for Debian Developers - DD_TUPLES = (('username', 'username'), - ('aliothusername', 'username')) - - def _get_label(self, section, url=None): - if section in self._LABELS: - if url: - if url in self._LABELS[section]: - return self._LABELS[section][url] - elif 'label' in self._LABELS[section]: - return self._LABELS[section]['label'] - if url: - return "%s.%s" % (section, url) - return section - - def index(self): - """ - Render the input form. - """ - return render('/showform.mako') - - def _build_request_params(self): - schema = DDDataRequest() - formencode.api.set_stdtranslation( - domain="FormEncode", - languages=[lang[0:2] for lang in request.languages]) - form_result = schema.to_python(request.params) - fields = dddatabuilder.build_data(form_result['email']) - rp = request.params.copy() - - if fields['type'] in (dddatabuilder.TYPE_DD, dddatabuilder.TYPE_DM): - for tuple in self.DM_TUPLES: - if not tuple[0] in rp or not rp[tuple[0]]: - rp[tuple[0]] = fields[tuple[1]] - if fields['type'] == dddatabuilder.TYPE_DD: - for tuple in self.DD_TUPLES: - if not tuple[0] in rp or not rp[tuple[0]]: - rp[tuple[0]] = fields[tuple[1]] - - return rp - - def urllist(self): - """Handle the actual data.""" - try: - rp = self._build_request_params() - except formencode.validators.Invalid as error: - c.messages = {'errors': error.unpack_errors()} - return render('/showform.mako') - - schema = DeveloperData() - try: - formencode.api.set_stdtranslation( - domain="FormEncode", - languages=[lang[0:2] for lang in request.languages]) - form_result = schema.to_python(rp) - except formencode.validators.Invalid, error: - c.messages = {'errors': error.unpack_errors()} - return render('/showform.mako') - if form_result['wikihomepage'] is None: - log.debug('generate wikihomepage from name') - form_result['wikihomepage'] = "".join( - [part.capitalize() for part in form_result['name'].split()]) - data = build_urls(form_result) - if form_result['mode'] == 'json': - response.headers['Content-Type'] = 'text/javascript' - return simplejson.dumps( - dict([("%s.%s" % (entry[1], entry[2].name), entry[3]) - for entry in data if entry[0] == 'url'])) - for entry in data: - if entry[0] in ('url', 'error'): - entry.append(_(self._get_label(entry[1], entry[2].name))) - elif entry[0] == 'section': - entry.append(_(self._get_label(entry[1]))) - c.urldata = data - return render('/showurls.mako') diff --git a/debianmemberportfolio/controllers/showformscripts.py b/debianmemberportfolio/controllers/showformscripts.py deleted file mode 100644 index 1e906a2..0000000 --- a/debianmemberportfolio/controllers/showformscripts.py +++ /dev/null @@ -1,75 +0,0 @@ -# -*- python -*- -# -*- coding: utf-8 -*- -# -# Debian Member Portfolio Service ShowformscriptsController. -# -# Copyright © 2009-2014 Jan Dittberner -# -# This file is part of the Debian Member Portfolio Service. -# -# Debian Member Portfolio Service is free software: you can redistribute it -# and/or modify 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. -# -# Debian Member Portfolio Service 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 . -# -""" -This file defines the ShowformscriptsController used to generate the JavaScript -code in forms. -""" - -import logging -import simplejson - -from pylons import request, response -from pylons.controllers.util import abort - -import formencode.api -import formencode.validators - -from debianmemberportfolio.lib.base import BaseController, render -from debianmemberportfolio.model.form import DDDataRequest -from debianmemberportfolio.model import dddatabuilder - -log = logging.getLogger(__name__) - - -class ShowformscriptsController(BaseController): - """This controller is used to support data entry in showform. - - It provides code for generating JavaScript as well as JSON - responses for autocompletion of fields.""" - - def index(self): - """ - This action generates the helper script for the showform page. - """ - response.headers['Content-Type'] = 'text/javascript; charset=utf-8' - return render('/showformscript.mako') - - def fetchdddata(self): - """ - This action fetches the data for a given mail address and - returns them as JSON. - """ - schema = DDDataRequest() - try: - formencode.api.set_stdtranslation( - domain="FormEncode", - languages=[lang[0:2] for lang in request.languages]) - form_result = schema.to_python(request.params) - except formencode.validators.Invalid, error: - errors = error.unpack_errors() - abort(400, "\n".join( - ["%s: %s" % (key, errors[key]) for key in errors])) - fields = dddatabuilder.build_data(form_result['email']) - log.debug(fields) - response.headers['Content-Type'] = 'text/plain' - return simplejson.dumps(fields) diff --git a/debianmemberportfolio/controllers/template.py b/debianmemberportfolio/controllers/template.py deleted file mode 100644 index b1f53e1..0000000 --- a/debianmemberportfolio/controllers/template.py +++ /dev/null @@ -1,55 +0,0 @@ -# -*- python -*- -# -*- coding: utf-8 -*- -# -# Debian Member Portfolio Service TemplateController -# -# Copyright © 2009-2014 Jan Dittberner -# -# This file is part of the Debian Member Portfolio Service. -# -# Debian Member Portfolio Service is free software: you can redistribute it -# and/or modify 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. -# -# Debian Member Portfolio Service 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 . -# -""" -This file contains the TemplateController used to render templates. -""" - -from debianmemberportfolio.lib.base import BaseController -from pylons.controllers.util import abort - - -class TemplateController(BaseController): - - def view(self, url): - """By default, the final controller tried to fulfill the request - when no other routes match. It may be used to display a template - when all else fails, e.g.:: - - def view(self, url): - return render('/%s' % url) - - Or if you're using Mako and want to explicitly send a 404 (Not - Found) response code when the requested template doesn't exist:: - - import mako.exceptions - - def view(self, url): - try: - return render('/%s' % url) - except mako.exceptions.TopLevelLookupException: - abort(404) - - By default this controller aborts the request with a 404 (Not - Found) - """ - abort(404) diff --git a/debianmemberportfolio/lib/__init__.py b/debianmemberportfolio/lib/__init__.py deleted file mode 100644 index 4937320..0000000 --- a/debianmemberportfolio/lib/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- python -*- -# -*- coding: utf-8 -*- -# -# Debian Member Portfolio Service lib package -# -# Copyright © 2009-2014 Jan Dittberner -# -# This file is part of the Debian Member Portfolio Service. -# -# Debian Member Portfolio Service is free software: you can redistribute it -# and/or modify 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. -# -# Debian Member Portfolio Service 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 . -# diff --git a/debianmemberportfolio/lib/app_globals.py b/debianmemberportfolio/lib/app_globals.py deleted file mode 100644 index cb4ea2b..0000000 --- a/debianmemberportfolio/lib/app_globals.py +++ /dev/null @@ -1,43 +0,0 @@ -# -*- python -*- -# -*- coding: utf-8 -*- -# -# Debian Member Portfolio Service application Globals -# -# Copyright © 2009-2014 Jan Dittberner -# -# This file is part of the Debian Member Portfolio Service. -# -# Debian Member Portfolio Service is free software: you can redistribute it -# and/or modify 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. -# -# Debian Member Portfolio Service 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 . -# -""" -The application's Globals object -""" - -from beaker.cache import CacheManager -from beaker.util import parse_cache_config_options - - -class Globals(object): - """ - Globals acts as a container for objects available throughout the - life of the application - """ - - def __init__(self, config): - """ - One instance of Globals is created during application - initialization and is available during requests via the - 'app_globals' variable - """ - self.cache = CacheManager(**parse_cache_config_options(config)) diff --git a/debianmemberportfolio/lib/base.py b/debianmemberportfolio/lib/base.py deleted file mode 100644 index 7746e92..0000000 --- a/debianmemberportfolio/lib/base.py +++ /dev/null @@ -1,55 +0,0 @@ -# -*- python -*- -# -*- coding: utf-8 -*- -# -# Debian Member Portfolio Service base controller -# -# Copyright © 2009-2014 Jan Dittberner -# -# This file is part of the Debian Member Portfolio Service. -# -# Debian Member Portfolio Service is free software: you can redistribute it -# and/or modify 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. -# -# Debian Member Portfolio Service 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 . -# -""" -The base Controller API - -Provides the BaseController class for subclassing. -""" -from pylons import tmpl_context as c, request -from pylons.controllers import WSGIController -from pylons.i18n import add_fallback -from pylons.templating import render_mako as render - - -class BaseController(WSGIController): - - def __call__(self, environ, start_response): - """Invoke the Controller""" - # WSGIController.__call__ dispatches to the Controller method - # the request is routed to. This routing information is - # available in environ['pylons.routes_dict'] - # set language environment - try: - languages = request.languages - for lang in languages: - try: - add_fallback(lang.replace('-', '_')) - except: - pass - except: - pass - c.messages = {'errors': [], 'messages': []} - return WSGIController.__call__(self, environ, start_response) - - -__all__ = ['BaseController', 'render'] diff --git a/debianmemberportfolio/lib/helpers.py b/debianmemberportfolio/lib/helpers.py deleted file mode 100644 index 9bcb5e2..0000000 --- a/debianmemberportfolio/lib/helpers.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- python -*- -# -*- coding: utf-8 -*- -# -# Debian Member Portfolio Service webhelpers -# -# Copyright © 2009-2014 Jan Dittberner -# -# This file is part of the Debian Member Portfolio Service. -# -# Debian Member Portfolio Service is free software: you can redistribute it -# and/or modify 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. -# -# Debian Member Portfolio Service 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 . -# -# pymode:lint_ignore=W0611 -# -"""Helper functions - -Consists of functions to typically be used within templates, but also -available to Controllers. This module is available to templates as 'h'. -""" -from webhelpers.html.builder import escape, literal -from webhelpers.html.tags import stylesheet_link, javascript_link, image, \ - form, text, radio, submit, end_form, link_to, checkbox -from webhelpers.text import truncate -from webhelpers.textile import textile -from pylons import url diff --git a/debianmemberportfolio/model/form.py b/debianmemberportfolio/model/form.py deleted file mode 100644 index b10ad95..0000000 --- a/debianmemberportfolio/model/form.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- python -*- -# -*- coding: utf-8 -*- -# -# Debian Member Portfolio Service form handling model -# -# Copyright © 2009-2014 Jan Dittberner -# -# This file is part of the Debian Member Portfolio Service. -# -# Debian Member Portfolio Service is free software: you can redistribute it -# and/or modify 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. -# -# Debian Member Portfolio Service 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 . -# -""" -This file contains the form definitions used in the controllers. -""" - -import formencode - - -class DeveloperData(formencode.Schema): - """Validation schema for DeveloperData.""" - allow_extra_fields = True - filter_extra_fields = True - email = formencode.validators.Email(not_empty=True) - name = formencode.validators.String(not_empty=True) - gpgfp = formencode.All(formencode.validators.PlainText(), - formencode.validators.MinLength(32), - formencode.validators.MaxLength(40)) - username = formencode.validators.PlainText() - nonddemail = formencode.validators.Email() - aliothusername = formencode.validators.PlainText() - mode = formencode.validators.OneOf([u'json', u'html'], if_missing=u'html') - forumsid = formencode.validators.Int(if_missing=None) - wikihomepage = formencode.validators.String(if_missing=None) - - -class DDDataRequest(formencode.Schema): - """Validation schema for DDData request.""" - allow_extra_fields = True - filter_extra_fields = False - email = formencode.validators.Email(not_empty=True) diff --git a/debianmemberportfolio/templates/base.mako b/debianmemberportfolio/templates/base.mako deleted file mode 100644 index 4df882f..0000000 --- a/debianmemberportfolio/templates/base.mako +++ /dev/null @@ -1,52 +0,0 @@ -## -*- coding: utf-8 -*- \ - -<%doc> -Base template for XHTML templates. -Copyright © 2009-2014 Jan Dittberner - -This file is part of the Debian Member Portfolio service. - -Debian Member Portfolio service is free software: you can redistribute it -and/or modify 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. - -Debian Member Portfolio service 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 . - - - - ${_('Debian Member Portfolio Service')}${self.titleaddon()} - ${h.stylesheet_link(h.url('/stylesheets/style.css'))} - ${self.extrahead()} - - - -
- ${self.body()} -
- - - - - -<%def name="extrahead()"> diff --git a/debianmemberportfolio/templates/showformscript.mako b/debianmemberportfolio/templates/showformscript.mako deleted file mode 100644 index 9cac439..0000000 --- a/debianmemberportfolio/templates/showformscript.mako +++ /dev/null @@ -1,122 +0,0 @@ -## -*- coding: utf-8 -*- \ -<%doc> -Helper JavaScript for the data input form. -Copyright © 2009, 2010, 2015 Jan Dittberner - -This file is part of DDPortfolio service. - -DDPortfolio service is free software: you can redistribute it and/or -modify 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. - -DDPortfolio service 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 -. -\ - -var defaulthiddendivs = new Array( - '#namefield', '#gpgfpfield', '#usernamefield', '#nonddemailfield', - '#aliothusernamefield', '#wikihomepagefield', '#forumsidfield'); -var maskedfielddivs = new Array( - '#namefield', '#gpgfpfield', '#usernamefield', '#nonddemailfield', - '#aliothusernamefield', '#wikihomepagefield', '#forumsidfield'); -var allfielddivs = new Array( - '#namefield', '#gpgfpfield', '#usernamefield', '#nonddemailfield', - '#aliothusernamefield', '#wikihomepagefield', '#forumsidfield'); - -function updateFields(data, textStatus) { - if (data.type == 2) { // DD - $('#name').attr('value', data.name).attr('readonly', 'readonly'); - $('#gpgfp').attr('value', data.gpgfp); - $('#username').attr('value', data.username).attr( - 'readonly', 'readonly'); - $('#nonddemail').attr('value', data.email).focus(); - $('#aliothusername').attr('value', data.username); - $('#wikihomepage').attr('value', data.wikihomepage); - - $('#namefield').show(); - $('#gpgfpfield').show(); - $('#usernamefield').show(); - $('#nonddemailfield').show(); - $('#aliothusernamefield').show(); - $('#wikihomepagefield').show(); - $('#forumsidfield').show(); - - $('#nonddemail').focus().select(); - } else if (data.type == 1) { // DM - $('#name').attr('value', data.name).attr('readonly', 'readonly'); - $('#gpgfp').attr('value', data.gpgfp); - $('#username').attr('value', ''); - $('#nonddemail').attr('value', data.email).focus(); - $('#wikihomepage').attr('value', data.wikihomepage); - - $('#namefield').show(); - $('#gpgfpfield').show(); - $('#usernamefield').hide(); - $('#nonddemailfield').hide(); - $('#aliothusernamefield').show(); - $('#wikihomepagefield').show(); - $('#forumsidfield').show(); - - $('#aliothusername').focus().select(); - } else { - $('#nonddemail').attr('value', data.email); - $('#name').removeAttr('readonly'); - $('#username').removeAttr('readonly').attr('value', ''); - $('#gpgfp').attr('value', ''); - - $('#usernamefield').hide(); - $('#gpgfpfield').hide(); - $('#nonddemailfield').hide(); - $('#namefield').show(); - $('#aliothusernamefield').show(); - $('#wikihomepagefield').show(); - $('#forumsidfield').show(); - - $('#name').focus().select(); - } -} - -function onChangeShowAll(event) { - if ($('#showall').prop('checked')) { - for (var fielddiv in allfielddivs) { - $(allfielddivs[fielddiv]).show(); - } - } else { - for (var fielddiv in maskedfielddivs) { - $(maskedfielddivs[fielddiv]).hide(); - } - } -} - -function onBlurEmail() { - if ($.trim($('#email').prop('value')).length > 0) { - $.ajax({ - 'url' : '${h.url(controller="showformscripts", action="fetchdddata")}', - 'data' : {'email' : $('#email').prop('value')}, - 'dataType' : 'json', - 'success' : updateFields, - 'error' : function(request, textStatus, errorThrown) { - $('#email').focus(); - } - }); - } -} - -$(document).ready(function() { - for (var index in defaulthiddendivs) { - if (!$(defaulthiddendivs[index]).hasClass('witherrors')) { - $(defaulthiddendivs[index]).hide(); - } - } - - $('#showall').attr('checked', false).change(onChangeShowAll); - $('#showallfield').show(); - $('#email').blur(onBlurEmail).focus(); -}); diff --git a/debianmemberportfolio/templates/showurls.mako b/debianmemberportfolio/templates/showurls.mako deleted file mode 100644 index 65358fd..0000000 --- a/debianmemberportfolio/templates/showurls.mako +++ /dev/null @@ -1,67 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="base.mako" />\ -<%doc> -Template for the url output page. -Copyright © 2009-2014 Jan Dittberner - -This file is part of Debian Member Portfolio Service. - -Debian Member Portfolio Service is free software: you can redistribute it -and/or modify 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. - -Debian Member Portfolio Service 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 . -\ -<%def name="titleaddon()"> - - ${_('Your personal links')} - -% if c.urldata: -
- ${_('Debian Member Portfolio')} - - - - - - % for row in c.urldata: - % if row[0] == 'section': - - <% urlclass = 'odd' %> - % elif row[0] == 'error': - - - - - % else: - - - - - <% - if urlclass == 'odd': - urlclass = 'even' - else: - urlclass = 'odd' - %> - % endif - % endfor - -
${_('Usage')}${_('URL')}
${h.literal(h.textile(row[4]))}${_('Error during URL creation:')} - ${row[3].replace("\n", - '
')}
${h.literal(h.textile(row[4]))} - % if row[2].type == 'url': - ${h.link_to(h.truncate(row[3], length=120), row[3])} - % else: - ${row[3]} - % endif -
-
-% endif -

${h.link_to(_('Restart'), h.url(controller='portfolio', action='index'))}

diff --git a/debianmemberportfolio/tests/__init__.py b/debianmemberportfolio/tests/__init__.py deleted file mode 100644 index 31fbc54..0000000 --- a/debianmemberportfolio/tests/__init__.py +++ /dev/null @@ -1,59 +0,0 @@ -# -*- python -*- -# -*- coding: utf-8 -*- -# -# Debian Member Portfolio Service tests package -# -# Copyright © 2009-2014 Jan Dittberner -# -# This file is part of the Debian Member Portfolio Service. -# -# Debian Member Portfolio Service is free software: you can redistribute it -# and/or modify 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. -# -# Debian Member Portfolio Service 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 . -# -""" -Pylons application test package - -When the test runner finds and executes tests within this directory, this file -will be loaded to setup the test environment. - -It registers the root directory of the project in sys.path and pkg_resources, -in case the project hasn't been installed with setuptools. It also initializes -the application via websetup (paster setup-app) with the project's test.ini -configuration file. -""" - -from unittest import TestCase - -from paste.script.appinstall import SetupCommand -from pylons import url -from routes.util import URLGenerator -from webtest import TestApp - -import pylons.test - -__all__ = ['environ', 'url', 'TestController'] - -# Invoke websetup with the current config file -SetupCommand('setup-app').run([pylons.test.pylonsapp.config['__file__']]) - -environ = {} - - -class TestController(TestCase): - - def __init__(self, *args, **kwargs): - wsgiapp = pylons.test.pylonsapp - config = wsgiapp.config - self.app = TestApp(wsgiapp) - url._push_object(URLGenerator(config['routes.map'], environ)) - TestCase.__init__(self, *args, **kwargs) diff --git a/debianmemberportfolio/tests/functional/__init__.py b/debianmemberportfolio/tests/functional/__init__.py deleted file mode 100644 index 75697f6..0000000 --- a/debianmemberportfolio/tests/functional/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- python -*- -# -*- coding: utf-8 -*- -# -# Debian Member Portfolio Service functional tests package -# -# Copyright © 2009-2014 Jan Dittberner -# -# This file is part of the Debian Member Portfolio Service. -# -# Debian Member Portfolio Service is free software: you can redistribute it -# and/or modify 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. -# -# Debian Member Portfolio Service 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 . -# diff --git a/debianmemberportfolio/tests/functional/test_portfolio.py b/debianmemberportfolio/tests/functional/test_portfolio.py deleted file mode 100644 index bebdbc8..0000000 --- a/debianmemberportfolio/tests/functional/test_portfolio.py +++ /dev/null @@ -1,43 +0,0 @@ -# -*- python -*- -# -*- coding: utf-8 -*- -# -# Debian Member Portfolio Service PortfolioController test -# -# Copyright © 2009-2014 Jan Dittberner -# -# This file is part of the Debian Member Portfolio Service. -# -# Debian Member Portfolio Service is free software: you can redistribute it -# and/or modify 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. -# -# Debian Member Portfolio Service 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 . -# -""" -This module defines test cases for the PortfolioController. -""" - -from debianmemberportfolio.tests import TestController, url - - -class TestPortfolioController(TestController): - """ - Test cases for PortfolioController. - """ - - def test_index(self): - """ - Test for the controller's index action. - """ - response = self.app.get(url(controller='portfolio', action='index')) - # Test response... - assert response.status_int == 200 - assert response.content_type == "text/html" - assert "Debian Member Portfolio Service" in response diff --git a/debianmemberportfolio/tests/functional/test_showformscripts.py b/debianmemberportfolio/tests/functional/test_showformscripts.py deleted file mode 100644 index d3da82a..0000000 --- a/debianmemberportfolio/tests/functional/test_showformscripts.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- python -*- -# -*- coding: utf-8 -*- -# -# Debian Member Portfolio Service ShowformscriptsController test -# -# Copyright © 2009-2014 Jan Dittberner -# -# This file is part of the Debian Member Portfolio Service. -# -# Debian Member Portfolio Service is free software: you can redistribute it -# and/or modify 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. -# -# Debian Member Portfolio Service 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 . -# -""" -This module defines test cases for the ShowformscriptsController. -""" - -from debianmemberportfolio.tests import TestController, url - - -class TestShowformscriptsController(TestController): - """ - Test cases for ShowformscriptsController. - """ - - def test_index(self): - """ - Test for the controller's index action. - """ - response = self.app.get( - url(controller='showformscripts', action='index')) - # Test response... - assert response.status_int == 200 - assert response.content_type == "text/javascript" - assert "function updateField" in response diff --git a/debianmemberportfolio/tests/test_models.py b/debianmemberportfolio/tests/test_models.py deleted file mode 100644 index 6d9b913..0000000 --- a/debianmemberportfolio/tests/test_models.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- python -*- -# -*- coding: utf-8 -*- -# -# Debian Member Portfolio Service model tests -# -# Copyright © 2009-2014 Jan Dittberner -# -# This file is part of the Debian Member Portfolio Service. -# -# Debian Member Portfolio Service is free software: you can redistribute it -# and/or modify 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. -# -# Debian Member Portfolio Service 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 . -# diff --git a/development.ini b/development.ini deleted file mode 100644 index db8dcc7..0000000 --- a/development.ini +++ /dev/null @@ -1,73 +0,0 @@ -# -# Debian Member Portfolio Service - Pylons development environment -# configuration -# -# The %(here)s variable will be replaced with the parent directory of this file -# -[DEFAULT] -debug = true -# Uncomment and replace with the address which should receive any error reports -#email_to = you@yourdomain.com -smtp_server = localhost -error_email_from = paste@localhost - -[server:main] -use = egg:Paste#http -host = 127.0.0.1 -port = 5000 - -[app:main] -use = egg:debianmemberportfolio -full_stack = true -static_files = true - -cache_dir = %(here)s/data -beaker.session.key = debianmemberportfolio -beaker.session.secret = somesecret - -# If you'd like to fine-tune the individual locations of the cache data dirs -# for the Cache data, or the Session saves, un-comment the desired settings -# here: -#beaker.cache.data_dir = %(here)s/data/cache -#beaker.session.data_dir = %(here)s/data/sessions - -# WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* -# Debug mode will enable the interactive debugging tool, allowing ANYONE to -# execute malicious code after an exception is raised. -#set debug = false - - -# Logging configuration -[loggers] -keys = root, routes, debianmemberportfolio - -[handlers] -keys = console - -[formatters] -keys = generic - -[logger_root] -level = INFO -handlers = console - -[logger_routes] -level = INFO -handlers = -qualname = routes.middleware -# "level = DEBUG" logs the route matched and routing variables. - -[logger_debianmemberportfolio] -level = DEBUG -handlers = -qualname = debianmemberportfolio - -[handler_console] -class = StreamHandler -args = (sys.stderr,) -level = NOTSET -formatter = generic - -[formatter_generic] -format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] [%(threadName)s] %(message)s -datefmt = %H:%M:%S diff --git a/jessiereq.pip b/jessiereq.pip deleted file mode 100644 index ecb99be..0000000 --- a/jessiereq.pip +++ /dev/null @@ -1,29 +0,0 @@ -Flask==0.10.1 -Jinja2==2.7.3 -MarkupSafe==0.23 -Werkzeug==0.9.6 -itsdangerous==0.24 -Babel==1.3 -Flask-Babel==0.9 -pytz==2012c -speaklater==1.3 -Flask-WTF==0.10.2 -WTForms==2.0.1 -#Babel==1.3 -#Beaker==1.6.4 -#FormEncode==1.2.6 -#Mako==1.0.0 -#MarkupSafe==0.23 -#Paste==1.7.5.1 -#PasteDeploy==1.5.2 -#PasteScript==1.7.5 -#Pygments==2.0.1 -#Pylons==1.0.1 -#Routes==2.0 -#Tempita==0.5.2 -#WebError==0.10.3 -#WebHelpers==1.3 -#WebOb==1.4 -#WebTest==2.0.16 -#nose==1.3.4 -#simplejson==3.6.5 diff --git a/test.ini b/test.ini deleted file mode 100644 index bbef5d2..0000000 --- a/test.ini +++ /dev/null @@ -1,21 +0,0 @@ -# -# Debian Member Portfolio Service - Pylons testing environment configuration -# -# The %(here)s variable will be replaced with the parent directory of this file -# -[DEFAULT] -debug = true -# Uncomment and replace with the address which should receive any error reports -#email_to = you@yourdomain.com -smtp_server = localhost -error_email_from = paste@localhost - -[server:main] -use = egg:Paste#http -host = 127.0.0.1 -port = 5000 - -[app:main] -use = config:development.ini - -# Add additional test specific configuration options as necessary. From 0df84e586f9c8d5de324285f7f73b03f9ee7e040 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Thu, 12 Nov 2015 22:19:24 +0100 Subject: [PATCH 092/266] Update meta information and documentation --- ChangeLog | 3 ++ MANIFEST.in | 3 +- config.py | 21 +++++++++ debianmemberportfolio/views.py | 2 +- docs/source/devdocs.rst | 83 ++++++++++++++-------------------- docs/source/sourcecode.rst | 60 +++--------------------- run.py | 24 +++++++++- setup.cfg | 19 ++++---- setup.py | 9 ++-- stretch.pip | 2 +- 10 files changed, 105 insertions(+), 121 deletions(-) diff --git a/ChangeLog b/ChangeLog index 838d2f7..675dbfe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2015-11-12 Jan Dittberner + * port to Python 3 and Flask + 2015-03-09 Jan Dittberner * apply patch for DMD link by Paul Wise diff --git a/MANIFEST.in b/MANIFEST.in index 8b85d82..5df1764 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,2 @@ -include debianmemberportfolio/config/deployment.ini_tmpl -recursive-include debianmemberportfolio/public * +recursive-include debianmemberportfolio/static * recursive-include debianmemberportfolio/templates * diff --git a/config.py b/config.py index 4345151..a77f89b 100644 --- a/config.py +++ b/config.py @@ -1,4 +1,25 @@ +# -*- python -*- # -*- coding: utf-8 -*- +# +# Debian Member Portfolio Service Flask configuration +# +# Copyright © 2015 Jan Dittberner +# +# This file is part of the Debian Member Portfolio Service. +# +# Debian Member Portfolio Service is free software: you can redistribute it +# and/or modify 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. +# +# Debian Member Portfolio Service 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 . +# WTF_CSRF_ENABLED = False diff --git a/debianmemberportfolio/views.py b/debianmemberportfolio/views.py index 70455db..338ba2f 100644 --- a/debianmemberportfolio/views.py +++ b/debianmemberportfolio/views.py @@ -25,7 +25,7 @@ import logging from debianmemberportfolio import app, babel from flask import g, make_response, request, render_template, abort -from flask.ext.babel import gettext as _, lazy_gettext as N_ +from flask.ext.babel import lazy_gettext as N_ from config import LANGUAGES from .forms import DeveloperData, DeveloperDataRequest from .model import dddatabuilder diff --git a/docs/source/devdocs.rst b/docs/source/devdocs.rst index 73b0626..8e03b5c 100644 --- a/docs/source/devdocs.rst +++ b/docs/source/devdocs.rst @@ -1,16 +1,15 @@ Development of Debian Member Portfolio Service ============================================== -The Debian Member Portfolio Service is implemented in `Python -`_ using the `Pylons -`_ web application -framework. +The Debian Member Portfolio Service is implemented in `Python 3 +`_ using the `Flask `_ web +application framework. The following sections describe how to setup a local development environment for the Debian Member Portfolio Service. All instructions assume that you work on a Debian system. You should use Python -2.7 for development. +3 for development. Setup of a local development ---------------------------- @@ -22,53 +21,48 @@ To start working on the source code you need to have `git`_ installed:: .. _git: http://www.git-scm.com/ The canonical git repository for the Debian Member Portfolio Service is -available at http://debianstuff.dittberner.info/git/debianmemberportfolio.git. +available at https://debianstuff.dittberner.info/git/debianmemberportfolio.git. To get a clone of the source code you change to a directory of your choice and invoke git clone:: cd ~/src - git clone http://debianstuff.dittberner.info/git/debianmemberportfolio.git + git clone https://debianstuff.dittberner.info/git/debianmemberportfolio.git -You should use `virtualenv`_ to separate the development environment from your +You should use `venv`_ to separate the development environment from your system wide Python installation. You can install virtualenv using:: - sudo aptitude install python-virtualenv + sudo aptitude install python3-venv -.. _virtualenv: https://pypi.python.org/pypi/virtualenv +.. _venv: https://docs.python.org/3/library/venv.html -When you have :command:`virtualenv` installed you should create a virtual +When you have :command:`pyvenv` installed you should create a virtual environment for Debian Member Portfolio Service development and install the requirements using `pip `_:: mkdir ~/.virtualenvs - virtualenv --distribute ~/.virtualenvs/dmportfolio + pyvenv ~/.virtualenvs/dmportfolio . ~/.virtualenvs/dmportfolio/bin/activate cd ~/src/debianmemberportfolio - pip install -r jessiereq.pip + pip install -r stretchreq.pip .. note:: The Debian Member Portfolio Service instance at http://portfolio.debian.net/ - is running on a Debian Jessie server, therefore :file:`jessiereq.pip` + is running on a Debian Stretch server, therefore :file:`stretchreq.pip` contains dependency versions matching that Debian release. The dependency download and installation into the virtual environment takes some time. -After you have your virtual environment ready you need to setup the project for -development:: - - python setup.py develop - Debian Member Portfolio Service needs the JQuery JavaScript library to function properly. The JQuery library is not included in the git clone and must be copied into the subdirectory -:file:`debianmemberportfolio/public/javascript/jquery`. On Debian systems you +:file:`debianmemberportfolio/static/javascript/jquery`. On Debian systems you can install the package libjs-jquery and place a symlink to the directory -:file:`/usr/share/javascript` into :file:`debianmemberportfolio/public`: :: +:file:`/usr/share/javascript` into :file:`debianmemberportfolio/static`: :: sudo aptitude install libjs-jquery - ln -s /usr/share/javascript debianmemberportfolio/public + ln -s /usr/share/javascript debianmemberportfolio/static Prepare for first startup ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -93,21 +87,19 @@ When you have both installed you can run:: The first synchronizes the keyrings in :file:`$HOME/debian/keyring.debian.org` with files on the `keyring.debian.org `_ host. And the second generates a key/value database in -:file:`debianmemberportfolio/model/keyringcache` that is used by the code. +:file:`debianmemberportfolio/model/keyringcache.db` that is used by the code. Run a development server ~~~~~~~~~~~~~~~~~~~~~~~~ -Pylons uses PasteScript to run a development server. You can run a development -server using:: +You can run a development server using:: - paster serve --reload development.ini + python3 run.py The output of this command should look like the following:: - Starting subprocess with file monitor - Starting server in PID 31377. - serving on http://127.0.0.1:5000 + * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) + * Restarting with stat You can now access your development server at the URL that is printed by the command. @@ -122,21 +114,17 @@ Add new URL Debian Member Portfolio Service uses a ini style configuration file :file:`debianmemberportfolio/model/portfolio.ini` to configure the generated URL patterns. The actual URL generation is done in -:py:class:`~debianmemberportfolio.controllers.portfolio.DdportfolioController` -in the -:py:meth:`~debianmemberportfolio.controllers.portfolio.DdportfolioController.urllist` -method. +:py:func:`~debianmemberportfolio.views.urllist`. If you want to add a new URL type you have to add a line in -:file:`portfolio.ini` and an entry in -:py:class:`~debianmemberportfolio.controllers.portfolio.DdportfolioController`'s -:py:attr:`~debianmemberportfolio.controllers.portfolio.DdportfolioController._LABELS` -dictionary. The top level dictionary keys correspond to sections in the ini -file. The dictionary values are dictionaries themselves that contain a special -key ``label`` that defines the label of the section in the output and keys for -each entry to be rendered in that section. The values in these sub-dictionaries -are strings marked for translation using the :py:func:`~pylons.i18n._` function from -:py:mod:`pylons.i18n`. +:file:`portfolio.ini` and an entry in :py:mod:`~debianmemberportfolio.views`'s +:py:attr:`~debianmemberportfolio.views._LABELS` dictionary. The top level +dictionary keys correspond to sections in the ini file. The dictionary values +are dictionaries themselves that contain a special key ``label`` that defines +the label of the section in the output and keys for each entry to be rendered +in that section. The values in these sub-dictionaries are strings marked for +translation using the :py:func:`~flask.ext.babel.lazy_gettext` function from +:py:mod:`flask.ext.babel`. The patterns in :file:`portfolio.ini` can contain the following placeholders that are filled at runtime: @@ -148,7 +136,7 @@ Placeholder Replacement %(email)s email address (URL encoded) %(emailnoq)s email address %(firstchar)s first character of the email address -%(forumsid)d forum user id +%(forumsid)s forum user id %(gpgfp)s GNUPG/PGP key fingerprint %(name)s full name (i.e. John Smith) %(username)s Debian user name @@ -158,10 +146,9 @@ Placeholder Replacement .. _alioth.debian.org: https://alioth.debian.org/ The replacement of placeholders is performed in the -:py:meth:`~debianmemberportfolio.controllers.portfolio.DdportfolioController.urllist` -method. And uses data from the Debian keyring. Access to the pre-parsed keyring -data is performed using the -:py:func:`~debianmemberportfolio.model.dddatabuilder.build_data` function of -the module :py:mod:`debianmemberportfolio.model.dddatabuilder`, which uses +:py:func:`~debianmemberportfolio.views.urllist` function. And uses data from +the Debian keyring. Access to the pre-parsed keyring data is performed using +the :py:func:`~debianmemberportfolio.model.dddatabuilder.build_data` function +of the module :py:mod:`debianmemberportfolio.model.dddatabuilder`, which uses several helper functions from :py:mod:`debianmemberportfolio.model.keyfinder` to access the key information. diff --git a/docs/source/sourcecode.rst b/docs/source/sourcecode.rst index 0755a34..1c5dd88 100644 --- a/docs/source/sourcecode.rst +++ b/docs/source/sourcecode.rst @@ -4,58 +4,16 @@ Source documentation The sections below contain mostly autogenerated documentation of the source code of the Debian Member Portfolio Service. -Controllers ------------ +Forms +----- -.. automodule:: debianmemberportfolio.controllers +.. automodule:: debianmemberportfolio.forms :members: -portfolio controller -~~~~~~~~~~~~~~~~~~~~ +Views +----- -.. automodule:: debianmemberportfolio.controllers.portfolio - :members: - -error controller -~~~~~~~~~~~~~~~~ - -.. automodule:: debianmemberportfolio.controllers.error - :members: - -showformscripts controller -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. automodule:: debianmemberportfolio.controllers.showformscripts - :members: - -template controller -~~~~~~~~~~~~~~~~~~~ - -.. automodule:: debianmemberportfolio.controllers.template - :members: - -Library code ------------- - -.. automodule:: debianmemberportfolio.lib - :members: - -app_globals -~~~~~~~~~~~ - -.. automodule:: debianmemberportfolio.lib.app_globals - :members: - -base -~~~~ - -.. automodule:: debianmemberportfolio.lib.base - :members: - -helpers -~~~~~~~ - -.. automodule:: debianmemberportfolio.lib.helpers +.. automodule:: debianmemberportfolio.views :members: Model @@ -70,12 +28,6 @@ dddatabuilder .. automodule:: debianmemberportfolio.model.dddatabuilder :members: -form -~~~~ - -.. automodule:: debianmemberportfolio.model.form - :members: - keyfinder ~~~~~~~~~ diff --git a/run.py b/run.py index 715fe63..c42503f 100755 --- a/run.py +++ b/run.py @@ -1,4 +1,26 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 +# -*- python -*- +# -*- coding: utf-8 -*- +# +# Debian Member Portfolio Service Flask runner +# +# Copyright © 2015 Jan Dittberner +# +# This file is part of the Debian Member Portfolio Service. +# +# Debian Member Portfolio Service is free software: you can redistribute it +# and/or modify 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. +# +# Debian Member Portfolio Service 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 . +# from debianmemberportfolio import app if __name__ == '__main__': diff --git a/setup.cfg b/setup.cfg index da36c32..00c4a19 100644 --- a/setup.cfg +++ b/setup.cfg @@ -12,29 +12,28 @@ doc-dir=docs/html make-dirs=1 [nosetests] -with-pylons = test.ini cover-package = debianmemberportfolio # Babel configuration [compile_catalog] -domain = debianmemberportfolio -directory = debianmemberportfolio/i18n +domain = messages +directory = debianmemberportfolio/translations statistics = true [extract_messages] charset = UTF-8 add_comments = TRANSLATORS: -output_file = debianmemberportfolio/i18n/debianmemberportfolio.pot +output_file = messages.pot width = 80 msgid_bugs_address = jan@dittberner.info [init_catalog] -domain = debianmemberportfolio -input_file = debianmemberportfolio/i18n/debianmemberportfolio.pot -output_dir = debianmemberportfolio/i18n +domain = messages +input_file = messages.pot +output_dir = debianmemberportfolio/translations [update_catalog] -domain = debianmemberportfolio -input_file = debianmemberportfolio/i18n/debianmemberportfolio.pot -output_dir = debianmemberportfolio/i18n +domain = messages +input_file = messages.pot +output_dir = debianmemberportfolio/translations previous = true diff --git a/setup.py b/setup.py index cfe9852..2a40f15 100644 --- a/setup.py +++ b/setup.py @@ -46,15 +46,16 @@ setup( author_email='jan@dittberner.info', url='http://debian-stuff.dittberner.info/debianmemberportfolio', license='AGPL-3.0+', - install_requires=["Flask>=0.10.1", 'babel>=0.9.6'], + install_requires=["Flask>=0.10.1", 'Babel>=1.3', 'Flask-Babel>=0.9'], packages=find_packages(exclude=['ez_setup']), include_package_data=True, test_suite='nose.collector', package_data={'debianmemberportfolio': - ['*.ini', 'i18n/*/LC_MESSAGES/*.mo']}, + ['*.ini', 'translations/*/LC_MESSAGES/*.mo']}, message_extractors={'debianmemberportfolio': [ ('**.py', 'python', None), - ('templates/**.mako', 'mako', None), - ('public/**', 'ignore', None)]}, + ('templates/**.html', 'jinja2', None), + ('templates/**.js', 'jinja2', None), + ('static/**', 'ignore', None)]}, zip_safe=False, ) diff --git a/stretch.pip b/stretch.pip index f8ad1c2..439ca0e 100644 --- a/stretch.pip +++ b/stretch.pip @@ -3,7 +3,7 @@ Jinja2==2.8 MarkupSafe==0.23 Werkzeug==0.10.4 itsdangerous==0.24 -Babel==1.3 +Babel==2.1.1 Flask-Babel==0.9 pytz==2012c speaklater==1.3 From 7adc53c31ec76a8fb1c18757e1713ee2d67e00a6 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Thu, 12 Nov 2015 22:20:15 +0100 Subject: [PATCH 093/266] Update german translation --- .../translations/de/LC_MESSAGES/messages.po | 290 +++++++++++------- 1 file changed, 181 insertions(+), 109 deletions(-) diff --git a/debianmemberportfolio/translations/de/LC_MESSAGES/messages.po b/debianmemberportfolio/translations/de/LC_MESSAGES/messages.po index 71f4b27..8eed91f 100644 --- a/debianmemberportfolio/translations/de/LC_MESSAGES/messages.po +++ b/debianmemberportfolio/translations/de/LC_MESSAGES/messages.po @@ -9,25 +9,34 @@ msgid "" msgstr "" "Project-Id-Version: Debian Member Portfolio Service 0.3.1\n" "Report-Msgid-Bugs-To: jan@dittberner.info\n" -"POT-Creation-Date: 2014-02-08 18:14+0100\n" -"PO-Revision-Date: 2014-02-08 18:03+0100\n" +"POT-Creation-Date: 2015-11-12 22:11+0100\n" +"PO-Revision-Date: 2015-11-12 22:14+0100\n" "Last-Translator: Jan Dittberner \n" +"Language: de\n" "Language-Team: de \n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 0.9.6\n" +"Generated-By: Babel 2.1.1\n" -#: debianmemberportfolio/controllers/portfolio.py:45 +#: debianmemberportfolio/forms.py:33 +msgid "JSON" +msgstr "JSON" + +#: debianmemberportfolio/forms.py:33 +msgid "HTML" +msgstr "HTML" + +#: debianmemberportfolio/views.py:39 msgid "Overview" msgstr "Überblick" -#: debianmemberportfolio/controllers/portfolio.py:46 +#: debianmemberportfolio/views.py:40 msgid "Debian Member's Package Overview" msgstr "Paketübersicht des Debian-Mitglieds" -#: debianmemberportfolio/controllers/portfolio.py:47 +#: debianmemberportfolio/views.py:41 msgid "" "Debian Member's Package Overview\n" "... showing all email addresses" @@ -35,11 +44,11 @@ msgstr "" "Paketübersicht des Debian-Mitglieds\n" "... mit allen E-Mailadressen" -#: debianmemberportfolio/controllers/portfolio.py:51 +#: debianmemberportfolio/views.py:45 msgid "Bugs" msgstr "Fehler" -#: debianmemberportfolio/controllers/portfolio.py:52 +#: debianmemberportfolio/views.py:46 msgid "" "bugs received\n" "(note: co-maintainers not listed, see #430986)" -#: debianmemberportfolio/controllers/portfolio.py:56 +#: debianmemberportfolio/views.py:50 msgid "bugs reported" msgstr "Berichtete Fehler" -#: debianmemberportfolio/controllers/portfolio.py:57 +#: debianmemberportfolio/views.py:51 msgid "user tags" msgstr "User Tags" -#: debianmemberportfolio/controllers/portfolio.py:58 +#: debianmemberportfolio/views.py:52 msgid "all messages (i.e., full text search for developer name on all bug logs)" msgstr "" "Alle Nachrichten (d.h. Volltextsuche nach dem Entwicklernamen in allen " "Fehlerlogs)" -#: debianmemberportfolio/controllers/portfolio.py:60 +#: debianmemberportfolio/views.py:54 msgid "WNPP" msgstr "WNPP" -#: debianmemberportfolio/controllers/portfolio.py:61 +#: debianmemberportfolio/views.py:55 msgid "correspondent for bugs" msgstr "Beitragender zu Fehlern" -#: debianmemberportfolio/controllers/portfolio.py:62 +#: debianmemberportfolio/views.py:56 msgid "one year open bug history graph" msgstr "Graph der Entwicklung offener Fehlerberichte über ein Jahr" -#: debianmemberportfolio/controllers/portfolio.py:65 +#: debianmemberportfolio/views.py:59 msgid "Build" msgstr "Build" -#: debianmemberportfolio/controllers/portfolio.py:66 +#: debianmemberportfolio/views.py:60 msgid "buildd.d.o" msgstr "buildd.d.o" -#: debianmemberportfolio/controllers/portfolio.py:67 +#: debianmemberportfolio/views.py:61 msgid "igloo" msgstr "Igloo" -#: debianmemberportfolio/controllers/portfolio.py:70 +#: debianmemberportfolio/views.py:64 msgid "Quality Assurance" msgstr "Qualitätssicherung" -#: debianmemberportfolio/controllers/portfolio.py:71 +#: debianmemberportfolio/views.py:65 msgid "maintainer dashboard" msgstr "Maintainer Dashboard" -#: debianmemberportfolio/controllers/portfolio.py:72 +#: debianmemberportfolio/views.py:66 msgid "lintian reports" msgstr "Lintian-Berichte" -#: debianmemberportfolio/controllers/portfolio.py:73 +#: debianmemberportfolio/views.py:67 msgid "full lintian reports (i.e. including \"info\"-level messages)" msgstr "" "vollständige Lintian-Berichte (d.h. inklusive Meldungen der Stufe " "\"info\")" -#: debianmemberportfolio/controllers/portfolio.py:75 +#: debianmemberportfolio/views.py:69 msgid "piuparts" msgstr "piuparts" -#: debianmemberportfolio/controllers/portfolio.py:76 +#: debianmemberportfolio/views.py:70 msgid "Debian patch tracking system" msgstr "Debian Nachverfolgungssystem für Patches" -#: debianmemberportfolio/controllers/portfolio.py:77 +#: debianmemberportfolio/views.py:71 msgid "Debian Url ChecKer" msgstr "Debian URL-Prüfer" -#: debianmemberportfolio/controllers/portfolio.py:80 +#: debianmemberportfolio/views.py:74 msgid "Mailing Lists" msgstr "Mailinglisten" -#: debianmemberportfolio/controllers/portfolio.py:81 +#: debianmemberportfolio/views.py:75 msgid "lists.d.o" msgstr "lists.d.o" -#: debianmemberportfolio/controllers/portfolio.py:82 +#: debianmemberportfolio/views.py:76 msgid "lists.a.d.o" msgstr "lists.a.d.o" -#: debianmemberportfolio/controllers/portfolio.py:83 +#: debianmemberportfolio/views.py:77 msgid "gmane" msgstr "Gmane" -#: debianmemberportfolio/controllers/portfolio.py:86 +#: debianmemberportfolio/views.py:80 msgid "Files" msgstr "Dateien" -#: debianmemberportfolio/controllers/portfolio.py:87 +#: debianmemberportfolio/views.py:81 msgid "people.d.o" msgstr "people.d.o" -#: debianmemberportfolio/controllers/portfolio.py:88 +#: debianmemberportfolio/views.py:82 msgid "oldpeople" msgstr "oldpeople" -#: debianmemberportfolio/controllers/portfolio.py:89 -#: debianmemberportfolio/controllers/portfolio.py:97 +#: debianmemberportfolio/views.py:83 debianmemberportfolio/views.py:91 msgid "Alioth" msgstr "Alioth" -#: debianmemberportfolio/controllers/portfolio.py:92 +#: debianmemberportfolio/views.py:86 msgid "Membership" msgstr "Mitgliedschaft" -#: debianmemberportfolio/controllers/portfolio.py:93 +#: debianmemberportfolio/views.py:87 msgid "NM" msgstr "NM" -#: debianmemberportfolio/controllers/portfolio.py:94 +#: debianmemberportfolio/views.py:88 msgid "DB information via finger" msgstr "DB-Informationen per finger" -#: debianmemberportfolio/controllers/portfolio.py:95 +#: debianmemberportfolio/views.py:89 msgid "DB information via HTTP" msgstr "DB-Informationen per HTTP" -#: debianmemberportfolio/controllers/portfolio.py:96 +#: debianmemberportfolio/views.py:90 msgid "FOAF profile" msgstr "FOAF-Profil" -#: debianmemberportfolio/controllers/portfolio.py:98 +#: debianmemberportfolio/views.py:92 msgid "Wiki" msgstr "Wiki" -#: debianmemberportfolio/controllers/portfolio.py:99 +#: debianmemberportfolio/views.py:93 msgid "Forum" msgstr "Forum" -#: debianmemberportfolio/controllers/portfolio.py:102 +#: debianmemberportfolio/views.py:96 msgid "Miscellaneous" msgstr "Sonstiges" -#: debianmemberportfolio/controllers/portfolio.py:103 +#: debianmemberportfolio/views.py:97 msgid "debtags" msgstr "debtags" -#: debianmemberportfolio/controllers/portfolio.py:104 +#: debianmemberportfolio/views.py:98 msgid "Planet Debian (name)" msgstr "Planet Debian (Name)" -#: debianmemberportfolio/controllers/portfolio.py:105 +#: debianmemberportfolio/views.py:99 msgid "Planet Debian (username)" msgstr "Planet Debian (Benutzername)" -#: debianmemberportfolio/controllers/portfolio.py:106 +#: debianmemberportfolio/views.py:100 msgid "links" msgstr "Links" -#: debianmemberportfolio/controllers/portfolio.py:107 +#: debianmemberportfolio/views.py:101 msgid "Debian website" msgstr "Debian Webseite" -#: debianmemberportfolio/controllers/portfolio.py:108 +#: debianmemberportfolio/views.py:102 msgid "Debian search" msgstr "Debian-Suche" -#: debianmemberportfolio/controllers/portfolio.py:109 +#: debianmemberportfolio/views.py:103 msgid "GPG public key via finger" msgstr "öffentlicher GPG-Schlüssel per finger" -#: debianmemberportfolio/controllers/portfolio.py:110 +#: debianmemberportfolio/views.py:104 msgid "GPG public key via HTTP" msgstr "öffentlicher GPG-Schlüssel per HTTP" -#: debianmemberportfolio/controllers/portfolio.py:111 +#: debianmemberportfolio/views.py:105 msgid "NM, AM participation" msgstr "NM-, AM-Mitwirkung" -#: debianmemberportfolio/controllers/portfolio.py:112 +#: debianmemberportfolio/views.py:106 msgid "Contribution information" msgstr "Debian Contributor-Informationen" -#: debianmemberportfolio/controllers/portfolio.py:115 +#: debianmemberportfolio/views.py:109 msgid "Information reachable via ssh (for Debian Members)" msgstr "Per ssh erreichbare Informationen (für Debian Mitglieder)" -#: debianmemberportfolio/controllers/portfolio.py:116 +#: debianmemberportfolio/views.py:110 msgid "owned debian.net domains" msgstr "Besitz von debian.net-Domains" -#: debianmemberportfolio/controllers/portfolio.py:117 +#: debianmemberportfolio/views.py:111 msgid "" -"MIA database" -" information" +"MIA " +"database information" msgstr "" "Informationen in der MIA-Datenbank" -#: debianmemberportfolio/controllers/portfolio.py:119 +#: debianmemberportfolio/views.py:113 msgid "Group membership information" msgstr "Information über Gruppenmitgliedschaften" -#: debianmemberportfolio/controllers/portfolio.py:122 +#: debianmemberportfolio/views.py:116 msgid "Ubuntu" msgstr "Ubuntu" -#: debianmemberportfolio/controllers/portfolio.py:123 +#: debianmemberportfolio/views.py:117 msgid "Available patches from Ubuntu" msgstr "Verfügbare Patches aus Ubuntu" -#: debianmemberportfolio/model/urlbuilder.py:40 +#: debianmemberportfolio/model/urlbuilder.py:43 msgid "Email address" msgstr "E-Mailadresse" -#: debianmemberportfolio/model/urlbuilder.py:41 +#: debianmemberportfolio/model/urlbuilder.py:44 msgid "Name" msgstr "Name" -#: debianmemberportfolio/model/urlbuilder.py:42 +#: debianmemberportfolio/model/urlbuilder.py:45 msgid "GPG fingerprint" msgstr "GPG-Fingerabdruck" -#: debianmemberportfolio/model/urlbuilder.py:43 +#: debianmemberportfolio/model/urlbuilder.py:46 msgid "Debian user name" msgstr "Debian-Benutzername" -#: debianmemberportfolio/model/urlbuilder.py:44 +#: debianmemberportfolio/model/urlbuilder.py:47 msgid "Non Debian email address" msgstr "Nicht-Debian-E-Mailadresse" -#: debianmemberportfolio/model/urlbuilder.py:45 +#: debianmemberportfolio/model/urlbuilder.py:48 msgid "Alioth user name" msgstr "Alioth-Benutzername" -#: debianmemberportfolio/model/urlbuilder.py:97 -#: debianmemberportfolio/model/urlbuilder.py:101 +#: debianmemberportfolio/model/urlbuilder.py:109 +#: debianmemberportfolio/model/urlbuilder.py:113 #, python-format msgid "Missing input: %s" msgstr "Fehlende Eingabe: %s" -#: debianmemberportfolio/templates/base.mako:25 -#: debianmemberportfolio/templates/base.mako:33 +#: debianmemberportfolio/templates/base.html:24 +#: debianmemberportfolio/templates/base.html:31 msgid "Debian Member Portfolio Service" msgstr "Debian-Mitglieder-Portfolioservice" -#: debianmemberportfolio/templates/base.mako:31 +#: debianmemberportfolio/templates/base.html:30 msgid "Debian Logo" msgstr "Debian-Logo" -#: debianmemberportfolio/templates/base.mako:34 +#: debianmemberportfolio/templates/base.html:32 msgid "" "This service has been inspired by Stefano Zacchiroli's DDPortfolio page in the " @@ -298,22 +306,22 @@ msgid "" "Debian Member's or package maintainer's information regarding Debian." msgstr "" "Dieser Dienst wurde durch Stefano Zacchirolis DDPortfolio-Seite im Debian " +"href=\"http://wiki.debian.org/DDPortfolio\">DDPortfolio-Seite im Debian " "Wiki inspiriert. Mit dem Dienst können personalisierte Links zu " "Informationen im Bezug auf Debian für Debian-Mitglieder und Paketbetreuer" " erzeugt werden." -#: debianmemberportfolio/templates/base.mako:41 +#: debianmemberportfolio/templates/base.html:39 msgid "AGPL - Free Software" msgstr "AGPL - Freie Software" -#: debianmemberportfolio/templates/base.mako:43 +#: debianmemberportfolio/templates/base.html:40 #, python-format msgid "" "The service is available 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. You can 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. You can browse the" " source code or clone it from %(cloneurl)s using Transifex." msgstr "" "Dieser Dienst wird unter den Bedingungen der GNU Affero General Public " +"href=\"http://www.gnu.org/licenses/agpl.html\">GNU Affero General Public " "License, so wie sie von der Free Software Foundation veröffentlicht " "ist, bereitgestellt. Sie können entweder Version 3 oder (auf Ihren Wunsch" " hin) jede spätere Version der Lizenz verwenden. Sie können sich Transifex dazu beitragen." -#: debianmemberportfolio/templates/base.mako:44 -msgid "Copyright © 2009-2014 Jan Dittberner" -msgstr "Copyright © 2009-2014 Jan Dittberner" +#: debianmemberportfolio/templates/base.html:41 +msgid "Copyright © 2009-2015 Jan Dittberner" +msgstr "Copyright © 2009-2015 Jan Dittberner" -#: debianmemberportfolio/templates/showform.mako:24 +#: debianmemberportfolio/templates/showform.html:22 msgid "Enter your personal information" msgstr "Eingabe der persönlichen Informationen" -#: debianmemberportfolio/templates/showform.mako:30 -#: debianmemberportfolio/templates/showurls.mako:27 +#: debianmemberportfolio/templates/showform.html:29 msgid "Debian Member Portfolio" -msgstr "Debian-Mitgliederportfolio" +msgstr "Debian-Mitglieder-Portfolioservice" -#: debianmemberportfolio/templates/showform.mako:36 +#: debianmemberportfolio/templates/showform.html:31 msgid "Email address:" msgstr "E-Mailadresse:" -#: debianmemberportfolio/templates/showform.mako:47 +#: debianmemberportfolio/templates/showform.html:40 msgid "Show all form fields" msgstr "Alle Formularfelder anzeigen" -#: debianmemberportfolio/templates/showform.mako:54 +#: debianmemberportfolio/templates/showform.html:43 msgid "Name:" msgstr "Name:" -#: debianmemberportfolio/templates/showform.mako:64 +#: debianmemberportfolio/templates/showform.html:50 msgid "GPG fingerprint:" msgstr "GPG-Fingerabdruck:" -#: debianmemberportfolio/templates/showform.mako:79 +#: debianmemberportfolio/templates/showform.html:57 msgid "Debian user name:" msgstr "Debian-Benutzername:" -#: debianmemberportfolio/templates/showform.mako:94 +#: debianmemberportfolio/templates/showform.html:64 msgid "Non Debian email address:" msgstr "Nicht-Debian-E-Mailadresse" -#: debianmemberportfolio/templates/showform.mako:109 +#: debianmemberportfolio/templates/showform.html:71 msgid "Alioth user name:" msgstr "Alioth-Benutzername:" -#: debianmemberportfolio/templates/showform.mako:125 +#: debianmemberportfolio/templates/showform.html:78 msgid "Wiki user name:" msgstr "Wiki-Benutzername:" -#: debianmemberportfolio/templates/showform.mako:140 +#: debianmemberportfolio/templates/showform.html:85 msgid "Forum user id:" msgstr "Forumsbenutzernummer:" -#: debianmemberportfolio/templates/showform.mako:151 +#: debianmemberportfolio/templates/showform.html:92 msgid "Output format:" msgstr "Ausgabeformat:" -#: debianmemberportfolio/templates/showform.mako:157 -msgid "HTML" -msgstr "HTML" - -#: debianmemberportfolio/templates/showform.mako:159 -msgid "JSON" -msgstr "JSON" - -#: debianmemberportfolio/templates/showform.mako:161 +#: debianmemberportfolio/templates/showform.html:99 msgid "Build Debian Member Portfolio URLs" msgstr "Debian-Mitgliedsportfolio-URLs bauen" -#: debianmemberportfolio/templates/showurls.mako:23 +#: debianmemberportfolio/templates/showurls.html:21 msgid "Your personal links" msgstr "Ihre personalisierten Links" -#: debianmemberportfolio/templates/showurls.mako:30 +#: debianmemberportfolio/templates/showurls.html:25 +msgid "Debian Member Porfolio" +msgstr "Debian-Mitgliederportfolio" + +#: debianmemberportfolio/templates/showurls.html:28 msgid "Usage" msgstr "Verwendung" -#: debianmemberportfolio/templates/showurls.mako:30 +#: debianmemberportfolio/templates/showurls.html:28 msgid "URL" msgstr "URL" -#: debianmemberportfolio/templates/showurls.mako:40 +#: debianmemberportfolio/templates/showurls.html:38 msgid "Error during URL creation:" msgstr "Fehler bei der URL-Erzeugung:" -#: debianmemberportfolio/templates/showurls.mako:67 +#: debianmemberportfolio/templates/showurls.html:59 msgid "Restart" msgstr "Neu beginnen" +#~ msgid "Debian Logo" +#~ msgstr "Debian-Logo" + +#~ msgid "" +#~ msgstr "" + +#~ msgid "AGPL - Free Software" +#~ msgstr "AGPL - Freie Software" + +#~ msgid "Copyright © 2009-2014 Jan Dittberner" +#~ msgstr "Copyright © 2009-2014 Jan Dittberner" + +#~ msgid "Debian Member Portfolio" +#~ msgstr "Debian-Mitgliederportfolio" + +#~ msgid "Email address:" +#~ msgstr "E-Mailadresse:" + +#~ msgid "Show all form fields" +#~ msgstr "Alle Formularfelder anzeigen" + +#~ msgid "Name:" +#~ msgstr "Name:" + +#~ msgid "GPG fingerprint:" +#~ msgstr "GPG-Fingerabdruck:" + +#~ msgid "Debian user name:" +#~ msgstr "Debian-Benutzername:" + +#~ msgid "Non Debian email address:" +#~ msgstr "Nicht-Debian-E-Mailadresse" + +#~ msgid "Alioth user name:" +#~ msgstr "Alioth-Benutzername:" + +#~ msgid "Wiki user name:" +#~ msgstr "Wiki-Benutzername:" + +#~ msgid "Forum user id:" +#~ msgstr "Forumsbenutzernummer:" + +#~ msgid "Output format:" +#~ msgstr "Ausgabeformat:" + +#~ msgid "HTML" +#~ msgstr "HTML" + +#~ msgid "JSON" +#~ msgstr "JSON" + +#~ msgid "Build Debian Member Portfolio URLs" +#~ msgstr "Debian-Mitgliedsportfolio-URLs bauen" + +#~ msgid "Your personal links" +#~ msgstr "Ihre personalisierten Links" + +#~ msgid "Usage" +#~ msgstr "Verwendung" + +#~ msgid "URL" +#~ msgstr "URL" + +#~ msgid "Error during URL creation:" +#~ msgstr "Fehler bei der URL-Erzeugung:" + +#~ msgid "Restart" +#~ msgstr "Neu beginnen" + From 8dc19247de1d69423ec1804b2297334393733cf7 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Thu, 31 Dec 2015 18:11:03 +0100 Subject: [PATCH 094/266] Add ribbon logo - R.I.P. Ian --- .../public/images/openlogo-ribbon-100.png | Bin 0 -> 6010 bytes debianmemberportfolio/templates/base.mako | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 debianmemberportfolio/public/images/openlogo-ribbon-100.png diff --git a/debianmemberportfolio/public/images/openlogo-ribbon-100.png b/debianmemberportfolio/public/images/openlogo-ribbon-100.png new file mode 100644 index 0000000000000000000000000000000000000000..1f0f8da7aac9263c347cc06d2f9e3423c9de5e48 GIT binary patch literal 6010 zcmV-=7lr7FP)FP!Xq&VB700+Qe7lMmc|)>&(vv(A34z4qFQqYMif+jSPN?y9EfG>tPPf~ucM z&0t`mf;&C)=ItpFbe^S{ zUjYAUt*j-EXoDKuQv|?<5Bcg^>Q!>;=&jZd$MY|uD+u6t__F2h1g+ji|KspmLFRcJ> zad3B)vic1xAz7eJ4N^tXNC=GueIHPeiavto9yU?OZY#Mx$>aMBq9=jlfW5$nz~c@b zzEjG}`>h0KfHpHo6~*5G?uEop)DIf?37dI^1}nK;2{VU*oRr%BajXYbUPeuwmEbht z91bB~R5LA9Me+T>eWYm&fQQ*)ZHzFg@p?{u?j#B_`QnFwerYi!ms$x=6Nl9xk8?&B z&4$N;8#1}CimmR`d}J%WDT2P_4&FL1LO~zktH9ghW7{& zdIlJs$$d-sVD0btV3?)&C{PCc)>~N3nfWexUjya>ozr2Y;hW{u-fO8(AP$Q`7BT90 zhv*-Hk~GMpz+#PB`hDI!eLZ`BfL%@2z}3KmK?GHd7zC;UI4ez-SC&z?z(S`$w7Nm6 znHF-{@MqE((gK?`Zdp02Uj@zwmI3*eD%=X(or*|mOa3FEr>DWQNyF#Lsa;{ITLN0W z4~epI2I(2&6NS1tW{k1GQtXZKGtw{yKq>W2|Da}uO3%5N@4%wR7}L{Ey+pLCL8>Sj zq0kSdAlt3rUWF=EIL`vZfTw^?mf{zZ;oxBoxTVxy4?L8LR>O(SH2pF=)q>HgP1a(H zmudL7B*K5IP}h}G6CXmI0=yLa*9OagFG6-+$N7xP>qc}LFeMeOLY+UInrE|-9@FbIYmyo2M)vnIDX_RACeF zIp7mZJ_j*_+CLH4pQy!3Tt7Itr{+p#&I}Uo2X@oxZjE}>hxbPg(aDBSCO^gjb z1TF;rX~`!6QPlT<17^8{bIo*Wzo}rUi{6kcc{v?rJ<6yPHR`KAmv(?Vxs)|)JY@>_ zC2*Og*j>N{z?+tQd@+-ncYxoR<(kO#m6V(mfm;=-L$2iIbb%_5$W0_F7X@8j#_F|3 z`JKR5EJf}IE(U5AQq(t0=wi^Lkx^O?#8{gZ>hB8o$x`aJWGBY`4LH|%OEl_s;Ix_4 zUbTqgel`!`g>?;CNKs#aM=0t9D&Ykym|aHQAC2PcfmfJ59o0-r+jE@^)-@y#=R)Au1voP_ zbn_wUW&EB6{KQhM4iUPxf?=aURU>`TRs|15aTdSHs7k1DSVLFro|SOM%xkl$KMo zITHru)NBQ|KE;3nk{Hnog<7l88qde1U_u!+-vQ_V+cVK22ss&LX`+5}j@_Eb?AZT@ z1AoBYKlMl@B`X#B7SOLmC^)a2+RfQAOID*yOsD1rNLaEwyOQFG02i~;F6ttNoQ$$G z%Euu3z8S3D2J{D>K}J0`c;Z2df2GhXKyP<&E}6xvIcX*`Ks2$SAjmzG6|4L6|oM+^Rs&zGrg$)L9_UxfsD0d$XI9YYgaLqqs*t`YH?TIyI%+;P%k~j{2l<-Q zS+Y%rw-EnSgNwRKikx}LZpa4n8I@L`wnF*5FTFmKz9)+cjK_G zA-iZQ0C=2jEaO94cFlJVhIU{7y8V5O7OYux_%h zXWjWbadWYtd@}*7a~d5V$ti{U4Dg!0I0@jZAlyV66U-3dS>6hw#HqO_pS-jp9@B+w z4Vk!u=)+NabIb*P9CXpeIoQVQn9JK13n}WWh;|Osd~zzMcMEiXisR8 zzH<^QA`6&U7)DzMRJ7D9JDiUAr@C9p|2^>aR7A0Li}>t(KqbZJS;}PwYqw3O=0~Y1 zL;tH}uVY-7_Z=b&0P@(MUrPNRTV1@!rVlv@*(lk^QugymWJ-d=&JQlpA321s074Gj zJ_nwglVUBSn$dk+n*SAaRH3>knxBlvjin0(z4XEVtGht&jIFKEjfnO3UlWM&E@}_(tJu%6XD}jVnCLWK+Xn7>jXKdqy`QNu7Bk{XjgEU9HZy_T+1?%ZVkx;mSAs;Er@?AEn@&Q@R+~pGI9$}Oa*uY)thkv0GLPD=9K{L{UFSq2wV~pt;VebK#yvsrDC_q1bKthTx7Yf}7>Jf0~ z$6~2`v4Dw%9oR7dLX(h$Hr^FaSHZkO_J8{eykWN?J_{r>$koWC%?282>K?Y_(*m-8 z!@X3aCo7!$H162g&ZmwZvdzHXfOVj^D;(vb`#4afVKRv^WE#{m2X}5Mb$`#LzL_A% zAYVWt(rtZRHv;!t@(4sVCF5N50}A~D@R7zD26_sa1ysBPEOl`f%wW~(*3mS5_!(pp z;&HWdiCjh>E~U?;))mpkt6>f}gBUp_gnO=(=(;G> zgz32HaONtph1VbhkcA;D|NdyYaU=b3TH1OqxaTD6Xmbgf*zG)1p^Je*E_#;(oiuE5 z;l&x$#rcz^oKHO*WTD9h?<4#B zJ_cwa`ZMrL-J_;EJ`wWmXbIaT-0g@<N2=n)s&`*%-t{ zk`6zUjHsNN=YU6iF5OT;QOZbx|-j7x%G88D+b(>Qjew4N{40 z_Rk7s)IOM)sZI6CBU;fKS=o+eq+^h0kwqq}lLLCw{ToVLG+s<$ zk<4t?@vD5;yi8&1qEAV=Mw<%byac(PPRZh2w9Zm2v$aW+kF2VJY zOUwah2*r14*%#u)Hc+2CT*>c`G?)h2jjX93wpgUajF_cS^Jtmsdp~f8L-V{$<8hC6 zcsunbWPjgb4Gf!3-9nepXe2>E934Qn`2k&Rfp`t+43s1ByKRD}7*MdA&fn7TZ4Mpo z(xBk(2157tpuc-8EdMGbi{~xCuiID`Ku%_JWRc6eDd$ZE4{3O}jM|E}((Q0SA#RNa z+FB74iy1LVqviry#X`n*&Evp$7c~y_=?>}y zjk^WdqH)%RQ0scpwQdqCa=r(!9qnjGJKE8XcC@1%?Py0k+R=`7w4)vEXh%ER(T;Wi zlEma_*(7vSC~1S(dG5aiI_xBL#Wk#KPI*%s!e)=50zM1;962Q|*XRgLqvfGu8KIgp z^EDf)kes_SyAge?nsGTh1hO@dX$_fzgnym^3;}u~k&fokc-f#k@MR>$$57-Du|nj) z;f%L#KSEKbe4NKHj^Nhtmna2oaa>Yb$Ta;@Es{Uin<*&m{D~>h0DOkTJib}w#VsT} z*u@=VmMbX9r*SaQW;wBvA=4)7LlV>UeUKwvK=K`$$jTt4tXk=!$0G;B#IZx;PHD>o zWvP%&A7UPZkju=@>oN8t+VG!2UA==l9yvPcT?hB<*cQ7Z7TFlYY2VPF z?-pw9Z5*-(HC6>^HLPjJ&Jf$dq6Lk_%=~OlA>q6Os}2M5LvO>wh;s$Ag2M_`DBE@0#x4 zy*_-7M-pkKx_2vy$Lsygpt&nn{{19;8i8vJKHZT`t0t{CWq2WQd+f!e`@H*r89vW^ zGGZu`{uJZ`Z%V>*5AZK0!#e_qcOmI9f(&J*V(Nix81>TBBQx#=J`cYGIWISkmyGK_ zKx%8M7ZnBm-O%M?A3ARm1BD!)l*tFEk&&QZ?yviOXfI6i?!14sUPc!oO@o)wDbscM9vQJ(s+~9yl7mz2T8uKfj5AKz$*a{^)@ZtIQ@NS%yZvo z8qa(q(j@jpnx8R1g%6)aB;qSRbSsf2@9V(8*xwDvV92EHPwZvY8W&d4a?hU^OAOjO zJ=caK{Z0JZoA~!rgJ}5yG;t_3?OzT4Z^i!oAuSC%75P%lhq}Z=)5GWbmkeFHBirec zo&2DX{=>^>vk%>6KJp@nQBC+Y!BZTh!!>g*-bC`V09OUp{FWy6r%TA`87v2Y)YFtZpyq!5o8=QnT$m9ESpR%(&|BsU1kxJ>%n0xm9 z(t-F*VuK9rx4XE&A+eu$nZ%dwh1mqfX?r8XJ};6T{b`*7b;#8o z5p#I&_m2Dw8+3ez@9Az~}k>VxO9>L4v#lzVo**i7zIVt0KrCeluXd6n{Yo@*1St zM`%`kvnffZIU0zJ20xz$Z5)2tk^IVn&N=jLg~B9G?NdEKP?Keqz@K2BSkhy)N$g0? z7hpcPSwqGk9jsZC>wy|%4goUR_4bi|FVxQz+Y1EONCTTsQG2TW&BR&(VjueGZ{A{&6Zy?V>ZctFWS%e86|#mNL+AAb!en1 zH2&K!3IFk#C=-BG>;A_Xzs&<$OoMp&nSI8i1h@HSMsB|^+%MQ8*@!g(4zS56D|veqdB4$^;lilCX_?>KoInem+_o4XJ#*Ayo>qc1zTDl)h z`hG@Pd{EHr!)rR3ueq4?$(o#jh|ejG2E@gY&b^S>3?&?gAg0goURV&hnu>xHO=U5r&^pynnADsm8r!%}BrF z#jVKvCWwz|Ft6ff4cm@*cJD_PxK{b_3OX8gjE@}ef?6Sm-22J?76PaGl$-uHzYp77 z5shPl4{eKdx#8FY2PyS#OsRW(uKBgS7vkR(2K^00hTQ4WYh*#n^j3S}w?47Vpee?G z={5eh9BGPA@VR!8!RuxpnxN*|Pq$xqJDdoIj!C@=8UA*SJ#;*fAimiDEHa|eNIN=& z#E8b_$bjKOB))bW(uDLtYUB.